BookShop项目 - 各模块功能

导读:各模块的开发逻辑架构

  1. 业务逻辑

    对项目的各部分进行开发时,首要任务是明确该部分的业务逻辑。明确任务逻辑后,才可能对html文件、dao层、service层、controller层有正确的操作。

  2. html文件

    明确session作用域中有哪些参数可以调用,部分参数对应的pojo类中的属性情况如何,然后对html文件使用thymeleaf进行渲染

  3. dao层

    根据业务逻辑,首先对涉及到的数据表进行必要的CRUD工作,使用的参数为对应的pojo类

  4. service层

    实现主要的业务逻辑,并为pojo类中的自建类属性赋值。

  5. controller层

    获取session中的对应参数或form表单中提交的参数,并创建service层实现业务时所需的参数,

    后调用service层内的业务方法,实现该部分的业务逻辑,

    在session中保存需要的变量

    并跳转至相应的组件或html文件上

  6. 对应的参数表
    序号 项目功能复杂时,可详细罗列各参数及对应的属性情况
    session参数
    form表单提交的参数

一、登录页面

  1. 业务逻辑

    tomcat的URL对应跳转到的时登陆页面,输入用户名和密码后,提交后,在t_user内查询是否有对应的数据:

    如果用户名或密码错误,就重新返回登录页面,

    如果用户名和密码正确,则跳转至book.do,加载图书列表

  2. 页面显示效果

  3. html
    <body>      <div class="msg_cont"><b></b><span class="errorMsg">请输入用户名和密码</span></div><div class="form"><form th:action="@{/user.do}" method="post"><input type="hidden" name="operate" value="login"/><label>用户名称:</label><!-- name名称要和数据库中的字段名一样 --><inputclass="itxt"type="text"placeholder="请输入用户名"autocomplete="off"tabindex="1"name="uname"value="lina"id="username"/><label>用户密码:</label><inputclass="itxt"type="password"placeholder="请输入密码"autocomplete="off"tabindex="1"name="pwd"value="ok"id="password"/><input type="submit" value="登录" id="sub_btn" /></form></div>
    </body>
    
  4. dao
    // 根据提交的用户名和密码,在t_user数据表内查询是否有对应的数据,如果有,则user不为空
    public class UserDAOImpl extends BaseDAO<User> implements UserDAO {@Overridepublic User getUser(Connection conn,String uname, String password) {String sql = "select * from t_user where uname = ? and pwd = ?";return super.singleCommonRetrieve(conn,sql,uname,password);}
    }
    
  5. service
    public class UserServiceImpl implements UserService {private UserDAO userDAO;@Overridepublic User getUser(Connection conn, String uname, String password) {return userDAO.getUser(conn,uname,password);}
    }
    
  6. controller
    public class UserController {private Connection conn = JdbcUtils.getConnection();private UserService userService;private CartItemService cartItemService;public String login(String uname, String pwd, HttpSession session) {User user = userService.getUser(conn,uname,pwd);// 如果在t_user数据表中查询到对应的数据,就将其保存在session作用域内if (user != null) {session.setAttribute("currUser",user);return "redirect:book.do";}// 如果返回数据为空,说明用户名或密码不存在,返回登录页面return "user/login";}
    }
    

二、主页面

  1. 业务逻辑

    主页面的图书列列表部分,需要读取数据库中t_book表内的数据进行实时渲染

  2. 页面显示效果

  3. html
    <!-- 主页面右上角的渲染设置 -->
    <div class="topbar-right" th:if="${session.currUser==null}"><a href="user/login.html" class="login">登录</a><a href="user/regist.html" class="register">注册</a><a href="cart/cart.html" class="cart iconfont icon-gouwuche">购物车<div class="cart-num" >3</div></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><!-- 跳转到cartController,执行其中的默认index方法,展示购物车的最新数据 --><a th:href="@{/cart.do}" class="cart iconfont icon-gouwuche" >购物车<divclass="cart-num" th:text="${session.currUser.cart.totalCount}">3</div></a><a href="./pages/manager/book_manager.html" class="admin">后台管理</a>
    </div><!-- 图书列表的渲染设置 -->
    <div class="list-content"><!-- th:object="${book} 后面但凡需要book的引用,直接用*即可"--><div  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.6</p><p th:text="|销量:*{saleCount}|">销量:230</p><p th:text="|库存:*{bookCount}|">库存:1000</p><button th:onclick="|addCart(*{id})|">加入购物车</button></div>
    </div>
    
  4. dao
    public class BookDAOImpl extends BaseDAO<Book> implements BookDAO {@Overridepublic List<Book> getBookList(Connection conn) {String sql = "select * from t_book where bookStatus = 0";List<Book> bookList = super.CommonRetrieve(conn, sql);return super.CommonRetrieve(conn,sql);}
    }
    
  5. service
    public class BookServiceImpl implements BookService {private BookDAO bookDAO;@Overridepublic List<Book> getBookList(Connection conn) {return bookDAO.getBookList(conn);}
    }
    
  6. controller
    public class BookController {private Connection conn = JdbcUtils.getConnection();private BookService bookService;// dispatcher的默认operate是indexpublic String index(HttpSession session) {List<Book> bookList = bookService.getBookList(conn);session.setAttribute("bookList",bookList);// index.html在/WEB-INF/pages/文件夹下,故不需要加多余路径return "index";}
    }
    

三、加入购物车(图书下侧的按钮)

  1. 业务逻辑

    点击图书后的"加入购物车"按钮,跳转到购物车页面

    如果该图书已经在购物车中,就数量加1,

    如果该图书不在购物车中,则在购物车中新增一列,并生成一条新的购物项cartItem

  2. 页面显示效果

  3. 业务分析,新增一个pojo

    由于购物车页面是由多条购物记录cart_item组成的,而且有“金额”、“商品总数量”、“总金额”等其它属性,且要分别罗列各条购物记录的详细信息,所以要新建一个pojo类,对应购物车页面。

    对应购物车中每条购物记录后的金额,应该在CartItem类中新加一个count属性

    public class Cart {// Map中存的是bookId和对应的CartItemprivate Map<Integer,CartItem> cartItemMap;// 所有图书的数量private Integer totalBookCount;// 所有图书的总价格private Double totalMoney;public Cart() {}public Map<Integer, CartItem> getCartItemMap() {return cartItemMap;}public void setCartItemMap(Map<Integer, CartItem> cartItemMap) {this.cartItemMap = cartItemMap;}// 图书总数量,只需要get方法即可public Integer getTotalBookCount() {totalBookCount = 0 ;if(cartItemMap!=null && cartItemMap.size()>0){for (CartItem cartItem : cartItemMap.values()){totalBookCount = totalBookCount + cartItem.getBuyCount() ;}}return totalBookCount;}// 图书的总金额,只需要get方法即可public Double getTotalMoney() {totalMoney = 0.0;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();BigDecimal bigDecimalPrice = new BigDecimal("" + cartItem.getBook().getPrice());BigDecimal bigDecimalBuyCount = new BigDecimal("" + cartItem.getBuyCount());BigDecimal bigDecimalTotalMoney = bigDecimalBuyCount.multiply(bigDecimalPrice);totalMoney = totalMoney + bigDecimalTotalMoney.doubleValue() ;}}return totalMoney;}
    }
    
    public class CartItem {private Integer id;private Book book;private Integer buyCount;private User userBean;private Double bookMoney;private Double count;public CartItem() {}public CartItem(Integer id) {this.id = id;}// 对于金额的计算,要将Double类型的数据转换为BigDecimal类public Double getCount() {BigDecimal bigDecimalPrice = new BigDecimal("" + getBook().getPrice());BigDecimal bigDecimalBuyCount = new BigDecimal("" + buyCount);BigDecimal bigDecimalCount = bigDecimalBuyCount.multiply(bigDecimalPrice);count = bigDecimalCount.doubleValue();return count;}
    }
    
  4. html
    <div class="w">            <tbody><tr th:each="cart:${session.currUser.cart.cartItemMap.values()}"><td><img th:src="@{|/static/uploads/${cart.book.bookImg}|}" alt="" /></td><td th:text="${cart.book.bookName}">活着</td><td><span class="count" th:onclick="|editCart(${cart.id},${cart.buyCount-1})|">-</span><input class="count-num" type="text" th:value="${cart.buyCount}" /><span class="count" th:onclick="|editCart(${cart.id},${cart.buyCount+1})|">+</span></td><td th:text="${cart.book.price}">36.8</td><td th:text="${cart.count}">36.8</td><td><a href="">删除</a></td></tr></tbody>
    </div><div class="footer-right"><div>共<span th:text="${session.currUser.cart.totalBookCount}">3</span>件商品</div><div class="total-price">总金额<span th:text="${session.currUser.cart.totalMoney}">99.9</span>元</div><a class="pay" th:href="@{/order.do?operate=checkout}">去结账</a>
    </div>
    
  5. dao
    public class CartItemImpl extends BaseDAO<CartItem> implements CartItemDAO {@Overridepublic List<CartItem> getCartList(Connection conn, User user) {String sql = "select * from t_cart_item where userBean = ?";List<CartItem> cartItems = super.CommonRetrieve(conn, sql, user.getId());return super.CommonRetrieve(conn,sql,user.getId());}@Overridepublic void addCartByBook(Connection conn, Book book,User user) {String sql = "insert into t_cart_item values(0,?,1,?)";super.update(conn,sql,book.getId(),user.getId());}@Overridepublic void updateCartByBook(Connection conn, Book book,CartItem cartItem) {String sql = "update t_cart_item set buyCount = ? where book = ?";super.update(conn,sql,cartItem.getBuyCount()+1,book.getId());}
    }
    
  6. service
    public class CartItemServiceImpl implements CartItemService {private CartItemDAO cartItemDAO;private BookService bookService;// 方法1:调用dao,获取当前用户的CartItem列表,并将其中的book属性全部赋值@Overridepublic List<CartItem> getCartItemList(Connection conn,User user) {List<CartItem> cartList = cartItemDAO.getCartList(conn, user);for (CartItem cartItem : cartList) {// 在bookDAO中,获取该购物项对应的book所有属性Book book = bookService.getBook(conn, cartItem.getBook().getId());// 给CartItem中的book属性赋值,保证其不为空cartItem.setBook(book);}return cartList;}// 方法2:给购物车对应的cart类中的map属性赋值,并给User类中的cart属性赋值@Overridepublic Cart getCart(Connection conn, User user) {List<CartItem> cartItemList = getCartItemList(conn,user);HashMap<Integer, CartItem> cartMap = new HashMap<>();for (CartItem cartItem : cartItemList) {cartMap.put(cartItem.getBook().getId(),cartItem);}Cart cart = new Cart();cart.setCartItemMap(cartMap);user.setCart(cart);return cart;}// 业务逻辑实现:根据购物车中是否有该书目,而调用不同的数据库处理方法@Overridepublic void addOrUpdateCartItem(Connection conn, Book book,User user) {Cart cart = getCart(conn,user);if (cart != null) {Map<Integer, CartItem> cartItemMap = cart.getCartItemMap();if (cartItemMap == null) {cartItemMap = new HashMap<Integer,CartItem>();}// 通过Map集合中是否包含给书的id,如果有,就执行修改操作if (cartItemMap.containsKey(book.getId())) {CartItem cartItem = cartItemMap.get(book.getId());cartItemDAO.updateCartByBook(conn,book,cartItem);} else {// 如果没有,就执行新增操作cartItemDAO.addCartByBook(conn,book,user);}} else {cartItemDAO.addCartByBook(conn,book,user);}}
    }
    
  7. controller
    public class CartController {private Connection conn = JdbcUtils.getConnection();private CartItemService cartItemService;// 加载当前用户的购物车的最新信息,因为将数据库中的数据修改后需要重新读取一下    public String index(HttpSession session){User user = (User)session.getAttribute("currUser");// 获取此时的当前用户的购物车Cart cart = cartItemService.getCart(conn, user);// 将购物车信息赋值给useruser.setCart(cart);// 将最新的user保存到作用域中,在html页面上,通过currUser渲染出来的数据就是最新的session.setAttribute("currUser",user);return "/cart/cart";}// 图书下侧的“加入购物车按钮”:向当前用户的购物车中添加或修改该图书     public String addCart(Integer bookId, HttpSession session) {User user = (User)session.getAttribute("currUser");cartItemService.addOrUpdateCartItem(conn,new Book(bookId),user);// 加载完成后,返回CartController,要重新加载一下cart页面return "redirect:cart.do";}
    }
    

四、去结算至我的订单

  1. 业务逻辑

    点击购物车页面的去结算按钮,直接生成一个新的订单,且生成多个对应的订单详情,插入数据库中对应的表中,并跳转至我的订单页面,展示最新的订单

    一个购物项cartItem对应一条订单详情orderItem

    一个购物车cart结算一次对应一个订单order

    一个订单order对应多个订单详情orderItem

  2. 页面效果

  3. html
    <tbody><tr th:each="order : ${session.orderList}"><td th:text="${order.orderNo}">12354456895</td><td th:text="${order.orderDate}">2015.04.23</td><td th:text="${order.orderMoney}">90.00</td><td th:text="${order.totalBookCount}">88</td><td><a href="" class="send">等待发货</a></td><td><a href="">查看详情</a></td></tr>
    </tbody>
    
  4. dao
    // 订单Order
    public class OrderDAOImpl extends BaseDAO<Order> implements OrderDAO {@Overridepublic Integer addOrder(Connection conn, Order order) {String sql = "insert into t_order values(0,?,?,?,?,0,?)";return super.update(conn,sql,order.getOrderNo(),order.getOrderDate(),order.getOrderUser().getId(),order.getOrderMoney(),order.getTotalBookCount());}@Overridepublic List<Order> getOrder(Connection conn, User user) {String sql = "select * from t_order where orderUser = ?";return super.CommonRetrieve(conn,sql,user.getId());}
    }// 订单详情orderItem
    public class OrderItemDAOImpl extends BaseDAO<OrderItem> implements OrderItemDAO {@Overridepublic void addOrderItem(Connection conn, OrderItem orderItem) {String sql = "insert into t_order_item values(0,?,?,?)";super.CommonRetrieve(conn,sql,orderItem.getBook().getId(),orderItem.getBuyCount(),orderItem.getOrderBean().getId());}
    }
    
  5. service
    public class OrderServiceImpl implements OrderService {private OrderDAO orderDAO;private OrderItemDAO orderItemDAO;private CartItemDAO cartItemDAO;// 在购物车中,点击去结算,在order中生成一条新的订单,同时要生成对应的多条订单详情OrderItem   @Overridepublic void addOrder(Connection conn, Order order) {Integer orderId = orderDAO.addOrder(conn, order);/*             每个orderItem对应的是每个cartItem,由于每次提交后,购物车会清空,所以t_cart_item中存着的只是当前购物车内的购物项。根据购物项中的数据,生成对应的订单详情*/User user = order.getOrderUser();for (CartItem cartItem : user.getCart().getCartItemMap().values()) {OrderItem orderItem = new OrderItem();orderItem.setBook(cartItem.getBook());orderItem.setBuyCount(cartItem.getBuyCount());orderItem.setOrderBean(new Order(orderId));orderItemDAO.addOrderItem(conn,orderItem);}        // 结算完成后,要清除购物车中的购物项for (CartItem cartItem : user.getCart().getCartItemMap().values()) {cartItemDAO.deleteCartItem(conn,cartItem);}}@Overridepublic List<Order> getOrder(Connection conn,User user) {return orderDAO.getOrder(conn,user);}
    }
    
  6. controller
    public class OrderController {private Connection conn = JdbcUtils.getConnection();private OrderService orderService;// 获取最新的所有订单,并将其存入session作用域    public String index(HttpSession session) {User user = (User)session.getAttribute("currUser");// 获取所有的订单详情List<Order> orderList = orderService.getOrder(conn, user);session.setAttribute("orderList",orderList);return "/order/order";}// 去结算后,将当前的结算的数据传入到order的各个属性中,生成新的order,并存入到数据库中public String checkout(HttpSession session) {// 创建order对象参数,保证service层的方法可以正常运行Order order = new Order();Date date = new Date();LocalDateTime now = LocalDateTime.now();int year = now.getYear();int month = now.getMonthValue();int day = now.getDayOfYear();int hour = now.getHour();int minute = now.getMinute();int second = now.getSecond();order.setOrderNo(UUID.randomUUID()+"_"+year+month+day+hour+minute+second);order.setOrderDate(date);User user = (User)session.getAttribute("currUser");order.setOrderUser(user);order.setOrderMoney(user.getCart().getTotalMoney());order.setTotalBookCount(user.getCart().getTotalBookCount());order.setOrderStatus(0);// 将参数传入service层orderService.addOrder(conn,order);return "redirect:order.do";}
    }
    

五、session过滤器

  1. 业务逻辑

    在多个html页面中,都会使用到thymeleaf进行渲染,如果session中的值不存在,则会引发页面显示错误,故需要添加session过滤器,保证session在没有值的情况下可靠跳转至登录页面

  2. 新建一个过滤器
    // 1.在注解中,存入可以在session不存在都可以通行的路径
    @WebFilter(urlPatterns = {"*.do","*.html"},initParams = {// 里面的value值中的逗号用来分割不同的路径,第二个是点击登录时会出现的路径@WebInitParam(name = "bai",value = "/bookshop/page.do?operate=page&page=user/login,/bookshop/user.do?null")})
    public class SessionFilter implements Filter {List<String> baiList = null;// 2.在init方法中提取在注解中存入的通行路径@Overridepublic void init(FilterConfig config) throws ServletException {// 得到注解中的bai的数据String baiStr = config.getInitParameter("bai");// 将@WegInitParam中的value内用逗号隔开的值变为数组String[] baiArr = baiStr.split(",");baiList = Arrays.asList(baiArr);}// 3.解析请求头中的路径信息,并进行逻辑判断是否要通行@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 3.1 转换成HeepServlet类型的HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;// 3.2 URI/URL/Query分别对应的值// request.getRequestURI = /bookshop/page.doSystem.out.println("request.getRequestURI = " + request.getRequestURI());//request.getRequestURL = http://localhost:8080/bookshop/page.doSystem.out.println("request.getRequestURL = " + request.getRequestURL());//request.getQueryString = operate=page&page=user/loginSystem.out.println("request.getQueryString = " + request.getQueryString());// 3.3 提取请求头中的URI/Query,并进行组装String uri = request.getRequestURI();String query = request.getQueryString();String str = uri + "?" + query;// 3.4 如果此次请求路径在bai中出现过,则说明该路径可以被执行if (baiList.contains(str)) {filterChain.doFilter(request,response);// 3.5 如果没有在bai中出现过,获取session中的currUser值} else {HttpSession session = request.getSession();Object currUserObj = session.getAttribute("currUser");// 3.5.1 如果session中的值为空,则跳转到登录页面if (currUserObj == null) {response.sendRedirect("page.do?operate=page&page=user/login");} else {// 3.5.2 如果session保存作用域中的currUser有值,则放行filterChain.doFilter(request,response);}}}@Overridepublic void destroy() {}
    }
    

六、注册页面(验证码技术:kaptcha.jar)

  1. 业务逻辑

    注册页面涉及到验证码(参考kaptcha的相关知识点),如果验证码不正确,就要重新回到注册页面。如果验证码正确,就将注册好的信息插入数据库中的t_user表,并跳转至登录页面

  2. 页面效果

  3. regist.html文件

    在input标签中要有name,否则提交之后获取到的是null值

    <form th:action="@{/user.do}" method="post"><input type="hidden" name="operate" value="regist"><div class="form-item"><div><label>用户名称:</label><input type="text" placeholder="请输入用户名" name="uname" value="宝2022" /></div><span class="errMess" >用户名应为6~16位数组和字母组成</span></div><div class="form-item"><div><label>用户密码:</label><input type="password" placeholder="请输入密码" name="pwd" value="ok"/></div><span class="errMess">密码的长度至少为8位</span></div><div class="form-item"><div><label>确认密码:</label><input type="password" placeholder="请输入确认密码" /></div><span class="errMess">密码两次输入不一致</span></div><div class="form-item"><div><label>用户邮箱:</label><input type="text" placeholder="请输入邮箱" name="email" value="bao@163.com"/></div><span class="errMess">请输入正确的邮箱格式</span></div><div class="form-item"><div><label>验证码:</label><div class="verify"><input type="text" placeholder="" name="verifyCode"/><img th:src="@{/kaptcha.jpg}" alt="" /></div></div><span class="errMess">请输入正确的验证码</span></div><button class="btn">注册</button>
    </form>
    
  4. dao
    public class UserDAOImpl extends BaseDAO<User> implements UserDAO {@Overridepublic void addUser(Connection conn, User user) {// t_user中的第一个字段为自增量,需要设置成0,但是不能为1,会与原本的数据冲突String sql = "insert into t_user values(0,?,?,?,0)";super.update(conn,sql,user.getUname(),user.getPwd(), user.getEmail());}
    }
    
  5. service
    public class UserServiceImpl implements UserService {private UserDAO userDAO;@Overridepublic void addUser(Connection conn, User user) {userDAO.addUser(conn,user);}
    }
    
  6. controller
    // 对应 user.do
    public class UserController {private Connection conn = JdbcUtils.getConnection();private UserService userService;// 方法头的参数是form表单中的name,必须保证完全一样public String regist(String uname,String pwd,String email,String verifyCode, HttpSession session) {// 1.获取kaptcha已经保存在session作用域中的验证码的值Object verifyCodeObj = (String)session.getAttribute("KAPTCHA_SESSION_KEY");// 2.如果该值为空,获知同表单中输入的验证码不一样,则重新返回到注册页面if (verifyCodeObj == null || !verifyCode.equals(verifyCodeObj)) {return "user/regist";} else {/* 3.如果表单中输入的验证码与session作用域中的验证码值一样,则将其增加到t_user表中,并进入登录页面*/if (verifyCode.equals(verifyCodeObj)) {userService.addUser(conn,new User(uname,pwd,email));return "user/login";}}return "user/login";}
    }
    

七、注册页面输入规范检测(正则表达式)

  1. 业务逻辑

    利用js中的正则表达式(Regular Express)对用户名、密码、邮箱的输入格式进行规范,不符合规范的输入会被提示,且不能提交至数据库

  2. 页面效果

  3. html
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"><head><script language="JavaScript" th:src="@{/static/script/regist.js}"></script></head><body><h1>注册尚硅谷会员</h1><form th:action="@{/user.do}" method="post" onsubmit="return preRegist() ;"><input type="hidden" name="operate" value="regist"/><div class="form-item"><div><label>用户名称:</label><input id="unameTxt" type="text" placeholder="请输入用户名" name="uname" value="h2022" /></div><span id="unameSpan" class="errMess" >用户名应为6~16位数组和字母组成</span></div><div class="form-item"><div><label>用户密码:</label><input id="pwdTxt" type="password" placeholder="请输入密码" name="pwd" value="ok"/></div><span id="pwdSpan" class="errMess">密码的长度至少为8位</span></div><div class="form-item"><div><label>确认密码:</label><input id="pwdTxt1" type="password" placeholder="请输入确认密码" name="pwd1" value="ok"/></div><span id="pwdSpan1" class="errMess">密码两次输入不一致</span></div><div class="form-item"><div><label>用户邮箱:</label><input id="emailTxt" type="text" placeholder="请输入邮箱" name="email" value="bao@163.com"/></div><span id="emailSpan" class="errMess">请输入正确的邮箱格式</span></div><div class="form-item"><div><label>验证码:</label><div class="verify"><input type="text" placeholder="" name="verifyCode"/><img th:src="@{/kaptcha.jpg}" alt="" /></div></div><span class="errMess">请输入正确的验证码</span></div><button class="btn">注册</button></form>       </body>
    </html>
    
  4. js
    function $(id){return document.getElementById(id);
    }function preRegist(){//用户名不能为空,而且是6~16位数字和字母组成var unameReg = /[0-9a-zA-Z]{6,16}/;var unameTxt = $("unameTxt");var uname = unameTxt.value ;var unameSpan = $("unameSpan");if(!unameReg.test(uname)){unameSpan.style.visibility="visible";return false ;}else{unameSpan.style.visibility="hidden";}// 密码的长度至少为8位var pwdReg = /\w{8,}/g;var pwdTxt = $("pwdTxt");var pwdSpan = $("pwdSpan");var pwd = pwdTxt.value;if (!pwdReg.test(pwd)) {pwdSpan.style.visibility="visible";return false;} else {pwdSpan.style.visibility="hidden";}// 密码两次输入不一致if ($("pwdTxt1").value!=$("pwdTxt").value) {$("pwdSpan1").style.visibility="visible";return false;} else {$("pwdSpan1").style.visibility="hidden";}// 请输入正确的邮箱格式var emailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;var emailTxt = $("emailTxt");var emailSpan = $("emailSpan");var email = emailTxt.value;if (!emailReg.test(email)) {emailSpan.style.visibility="visible";return false;} else {emailSpan.style.visibility="hidden";}return true;
    }
    

八、注册页面用户名的监测(Ajax异步请求)

  1. 业务逻辑

    使用Ajax异步请求技术,对页面进行局部刷新,监测用户名是否可以注册,如果在t_user内由该名称,则不可以注册。

  2. 页面效果

  3. 使用浏览器调试程序

  4. html
     <div><label>用户名称:</label><input id="unameTxt" type="text" placeholder="请输入用户名" name="uname"           value="h2022" onblur="ckUname(this.value)"/>
    </div>
    
  5. js
    // 如果我们想要发送一个异步请求,我们需要一个关键的对象 XMLHttpRequest
    var xmlHttpRequest;// 该方法用于针对不同的浏览器,创建正确的XMLHttpRequest对象。该方法会被封装在Axios框架内,此处了解即可
    function createXMLHttpRequest() {// 针对符合DOM2标准的浏览器if (window.XMLHttpRequest) {xmlHttpRequest = new XMLHttpRequest();// 针对不符合DOM2标准的且不同版本的IE浏览器} else if (window.ActiveXObject) {try {xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");} catch (e) {xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");}}
    }function ckUname(uname) {createXMLHttpRequest();var url = "user.do?operate=ckUname&uname="+uname;// 第一个参数:以什么样的方式发送;第二个参数:给谁发请求;第三个参数:是否为异步方式xmlHttpRequest.open("GET",url,true);// 设置回调函数,并创建。  readyState有0-4这几种状态xmlHttpRequest.onreadystatechange = ckUnameCB;// 发送请求xmlHttpRequest.send();
    }function ckUnameCB() {if (xmlHttpRequest.readyState==4 && xmlHttpRequest.status==200) {// xmlHttpRequest.responseText:服务器端响应给我的文本内容alert(xmlHttpRequest.responseText);if (xmlHttpRequest.responseText == "{'uname':'1'}") {alert("用户可以注册");} else {alert("用户已存在");}}
    }
    
  6. dao
    public class UserDAOImpl extends BaseDAO<User> implements UserDAO {@Overridepublic User getUser(Connection conn, String uname) {String sql = "select * from t_user where uname = ?";return super.singleCommonRetrieve(conn,sql,uname);}
    }
    
  7. service
    public class UserServiceImpl implements UserService {private UserDAO userDAO;@Overridepublic User getUser(Connection conn, String uname) {return userDAO.getUser(conn,uname);}
    }
    
  8. controller
    public class UserController {private Connection conn = JdbcUtils.getConnection();private UserService userService;public String ckUname(String uname) {User user = userService.getUser(conn,uname);if (user == null) {// 用户名可以注册return "json:{'uname':'1'}";} else {return "json:{'uname':'0'}";}}
    }
    
  9. servlet
    // 在dispatchServlet类内的返回值判断部分的修改
    if (retrunStr.startsWith("redirect:")) {String redirectStr = retrunStr.substring("redirect:".length());resp.sendRedirect(redirectStr);
    } else if (retrunStr.startsWith("json:")) {String jsonStr = retrunStr.substring("json:".length());// 将json后的内容发给客户端PrintWriter out = resp.getWriter();out.print(jsonStr);out.flush();
    }else {// 5.3 将controller内返回的模板传入父类的模板处理方法super.processTemplate(retrunStr,req,resp);
    }
    

九、购物车功能改造(Vue+Axios)

  1. 业务逻辑

    不再通过session来传递数据,改用Vue+Axios在前后端之间传输JSON数据

  2. 注意

    thymeleaf会自动解析pojo类中的get方法

    Axios进行的时前后端分离,value表达式获取的只是服务端响应的JSON数据

  3. 前端
    html
    <!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>Document</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}" /><script language="JavaScript" th:src="@{/static/script/vue.js}"></script><script language="JavaScript" th:src="@{/static/script/axios.min.js}"></script><script language="JavaScript" th:src="@{/static/script/edit.js}"></script><base th:href="@{/}"/></head><body>    <div class="list" id="cart_div"><div class="w"><table><thead><tr><th>图片</th><th>商品名称</th><th>数量</th><th>单价</th><th>金额</th><th>操作</th></tr></thead><tbody><!-- cart:在vue中通过value在响应中获得了 --><tr v-for="cartItem in cart.cartItemMap" ><td><img v-bind:src="'static/uploads/'+cartItem.book.bookImg" alt="" /></td><td >{{cartItem.book.bookName}}</td><td><span class="count" v-on:click="editCart(cartItem.id,cartItem.buyCount-1)">-</span><input class="count-num" type="text" v-bind:value="cartItem.buyCount" /><span class="count" v-on:click="editCart(cartItem.id,cartItem.buyCount+1)">+</span></td><td>{{cartItem.book.price}}</td><td>{{cartItem.count}}</td><td><a href="">删除</a></td></tr></tbody></table><div class="footer"><div class="footer-left"><a href="#" class="clear-cart">清空购物车</a><a href="#">继续购物</a></div><div class="footer-right"><div>共<span>{{cart.totalBookCount}}</span>件商品</div><div class="total-price">总金额<span>{{cart.totalMoney}}</span>元</div><a class="pay" th:href="@{/order.do?operate=checkout}">去结账</a></div></div></div></div></body>
    </html>
    js
    // 当页面加载的时候
    window.onload=function (){var vue = new Vue({el:"#cart_div",data:{cart:{}},methods:{// 在methods中创建了一个getCart方法getCart:function (){// 方法内发了一个axios请求axios({method:"POST",url:"cart.do",params:{operate:'cartConfig'}}).then(function (value){// value是接收服务端响应回的内容,data指其中的数据var cart = value.data;vue.cart = cart;}).catch(function (reason){});},editCart:function (cartId1,buyCount1){axios({method:"POST",url:"cart.do",// 普通传参params:{operate:'editCart',cartId:cartId1,buyCount:buyCount1}}).then(function (value){// 修改后重新执行一次getCart,加载最新的购物车情况vue.getCart();}).catch(function (reason){});}},// 在数据渲染的时候mounted:function () {this.getCart();}});
    }
    
  4. service
    public class CartItemServiceImpl implements CartItemService {private CartItemDAO cartItemDAO;private BookService bookService;// 获取当前用户的CartItem列表,并将其中的book属性全部赋值@Overridepublic List<CartItem> getCartItemList(Connection conn,User user) {List<CartItem> cartList = cartItemDAO.getCartList(conn, user);for (CartItem cartItem : cartList) {Book book = bookService.getBook(conn, cartItem.getBook().getId());cartItem.setBook(book);// 此处调用getCount方法执行内部的代码,因为axios框架不会在解析返回值时自动加载get方法cartItem.getCount();}return cartList;}// 给购物车对应的cart类中的map属性赋值,并将所有的cart赋值到User类中的cart属性中@Overridepublic Cart getCart(Connection conn, User user) {List<CartItem> cartItemList = getCartItemList(conn,user);HashMap<Integer, CartItem> cartMap = new HashMap<>();for (CartItem cartItem : cartItemList) {cartMap.put(cartItem.getBook().getId(),cartItem);}Cart cart = new Cart();cart.setCartItemMap(cartMap);// cart内的get方法也要全部执行一次,因为Axios不会自动调用get方法的cart.getTotalCount();cart.getTotalBookCount();cart.getTotalMoney();user.setCart(cart);return cart;}
    }
  5. controller
    public class CartController {private Connection conn = JdbcUtils.getConnection();private CartItemService cartItemService;public String editCart(Integer cartId,Integer buyCount) {cartItemService.updateCartById(conn,buyCount,cartId);return "json:";}public String cartConfig(HttpSession session) {User user = (User)session.getAttribute("currUser");// 获取此时的当前用户的购物车Cart cart = cartItemService.getCart(conn, user);Gson gson = new Gson();String cartJsonStr = gson.toJson(cart);return "json:"+cartJsonStr;}
    }
    

JavaWEB二十一:BookShop项目 - 各模块功能相关推荐

  1. JavaScript 编程精解 中文第三版 二十一、项目:技能分享网站

    二十一.项目:技能分享网站 原文:Project: Skill-Sharing Website 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了<JavaScri ...

  2. JavaWEB十七:bookShop项目 - 错误总结

    bookShop项目 - 错误总结 在form表单中,action必须写成th:action action必须写成th:action,这样才会转到/user.do对应的controller上<f ...

  3. 基于eclipse的android项目实战—博学谷(二十一)安卓更换头像功能(实测Android9及以下版本可用)

    本项目是用eclipse软件编写,经过我的亲自实践,其真实有效,希望能给您有所帮助

  4. javaweb(二十一)——JavaWeb的两种开发模式

    一.JSP+JavaBean开发模式 1.1.jsp+javabean开发模式架构 jsp+javabean开发模式的架构图如下图(图1-1)所示 图1-1 在jsp+javabean架构中,JSP负 ...

  5. python 日志输出为json格式文件_Py修行路 python基础 (二十一)logging日志模块 json序列化 正则表达式(re)...

    一.日志模块 两种配置方式:1.config函数 2.logger #1.config函数 不能输出到屏幕 #2.logger对象 (获取别人的信息,需要两个数据流:文件流和屏幕流需要将数据从两个数据 ...

  6. 02.javaWeb旅游网小项目【注册功能】

    用户注册模块 1.实现注册功能 1)注册功能(前台页面) 前台注册页面注册校验成功 使用异步交互(JQuery-ajax) 点击注册 将当前提交内容从后台数据库查询是否存在 $(function () ...

  7. JAVAWEB校园二手平台项目

    JAVAWEB校园二手平台项目 JavaWeb项目:JAVAWEB校园二手平台项目 此项目为本人的Java大作业. 前台代码:代码已经上传到github上 下载地址  Github 一.项目概况 1. ...

  8. Python入门(二十一)- 常见模块

    二十一.常见模块 上一章介绍了Python模块的相关知识,在实际开发中,Python的很多功能都已经有了成熟的第三方实现,一般不需要开发者"重复造轮子",当开发者需要完成某种功能时 ...

  9. 基层教学组织评估系统5_系统管理员数据维护模块功能完善,优化教学组织名称的输入提示补全,项目打包部署篇

    目录 一.完善 二.项目打包 三.部署 四.报错解决 五.数据初始 一.完善 系统管理员数据维护模块功能完善 优化教学组织名称的输入提示补全 数据对应格式bug修复 1.系统管理员数据维护模块功能完善 ...

最新文章

  1. js时间搓化为今天明天_打乒乓球的搓球技巧!你掌握了吗?
  2. 固定资产多提折旧问题
  3. 【.net 深呼吸】自定义应用程序配置节
  4. 自我学习的技巧和建议
  5. html 消息通知声音,ajax实现web页面的消息实时提醒时播放提示音
  6. DOTNET零碎总结---VB.NET修改数据存在多个txtbox时,SQL语句的操作
  7. 自动驾驶公司 | 纵目科技完成D轮1.9亿美元融资
  8. 百度音乐 android,百度音乐旧版本
  9. 阿里巴巴JAVA开发手册最新版pdf
  10. 向量点积衡量相似度_向量点积与叉积
  11. java枚举处理工具
  12. java计算时间差 (日时分秒)
  13. 音视频处理基础知识扫盲:数字视频YUV像素表示法以及视频帧和编解码概念介绍
  14. 一些开源代码网站介绍(持续添加中....)
  15. c++ stl栈容器stack用法介绍
  16. 单片机交通灯灯c语言程序,关于LED模拟交通灯单片机C语言程序设计 - 全文
  17. java单根结构_Java语言程序设计中的单根结构
  18. 微信接口验证类php,微信公众平台消息接口校验与消息接口响应实例
  19. 如果移动办公OA行业也有世界杯,OA厂商谁能夺冠?
  20. solidity 合约继承

热门文章

  1. echarts-环形图
  2. QT:通过按钮调用qpaintEvent事件实现自定义绘图
  3. 关于酷我音乐盒在Windows2003系统中无法运行的解决方案
  4. 直击2020国际工业智能展览会,百超迪能携明星产品款款而来
  5. 散射理论方程_第十五讲 ISAR成像雷达
  6. 线性代数学习笔记——二次型与二次曲面
  7. Techsmith Camtasia Studio 2022.0.2屏幕录制软件
  8. 很久没写了,发个策划书如何?
  9. Educational Codeforces Round 101 D. Ceil Divisions(构造)
  10. 0.5mm的焊锡丝能吃多大电流_貌似简单无奇的操作步骤 或许就能让你前功尽弃