Web项目系列文章推荐: |
---|
👉 JavaWeb企业实战项目(一):环境搭建-用户注册-邮件发送 |
👉 JavaWeb企业实战项目(二):用户登录-首页详情-商品分类 |
👉 JavaWeb企业实战项目(四):订单模块 |
👉 JavaWeb企业实战项目(五):后台模块1 |
👉 JavaWeb企业实战项目(六):后台模块2 |
👉 待更新 |
1、任务总述
1、带有分页查看分类下的商品信息
2、购物模块_模型抽取
3、购物模块_添加商品到购物车
4、购物模块_移除购物项
5、购物模块_清空购物车
2、查询类别下的商品信息_带有分页
SQL代码分析:
#查看类别cid=1的商品信息
SELECT * FROM product WHERE cid = 1 LIMIT ? ,?
#统计类别为1的商品的数量
SELECT COUNT(*) FROM product WHERE cid = 1
原理如下:
步骤实现:
1、准备工作 /jsp/header.jsp
<a href='/store_v5/ProductServlet?method=findProductsByCidWithPage&curPage=1&cid="+obj.cid+"'>"+obj.cname+"</a></li>";
2、创建PageModel类对象
public class PageModel {
//基本属性
private int currentPageNum;//当前页数,由用户指定 *
private int pageSize = 6;//每页显示的条数,固定的 *
private int totalRecords;//总记录条数,数据库查出来的 *
private int totalPageNum;//总页数,计算出来的 *
private int startIndex;//每页开始记录的索引,计算出来的 *
private int prePageNum;//上一页 *
private int nextPageNum;//下一页 *
private List<Product> list;//已经分好页的结果集,该list中只有10条记录
//扩展属性
//一共每页显示9个页码按钮
private int startPage;//开始页码
private int endPage;//结束页码
//完善属性
private String url;//也可不必写
//要想使用我的分页,必须给我两个参数。一个是要看哪一页,另一个是总记录条数
public PageModel(int currentPageNum,int totalRecords,int pageSize){
this.currentPageNum = currentPageNum;
this.totalRecords = totalRecords;
this.pageSize=pageSize;
//计算查询记录的开始索引
startIndex = (currentPageNum-1)*pageSize;
//计算总页数
totalPageNum = totalRecords%pageSize==0?(totalRecords/pageSize):(totalRecords/pageSize+1);
startPage = currentPageNum - 4; //5
endPage = currentPageNum + 4; //13
//看看总页数够不够9页
if(totalPageNum>9){
//超过了9页
if(startPage < 1){
startPage = 1;
endPage = startPage+8;
}
if(endPage>totalPageNum){
endPage = totalPageNum;
startPage = endPage-8;
}
}else{
//不够9页
startPage = 1;
endPage = totalPageNum;
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getStartPage() {
return startPage;
}
public void setStartPage(int startPage) {
this.startPage = startPage;
}
public int getEndPage() {
return endPage;
}
public void setEndPage(int endPage) {
this.endPage = endPage;
}
public int getPrePageNum() {
prePageNum = currentPageNum-1;
if(prePageNum<1){
prePageNum = 1;
}
return prePageNum;
}
public int getNextPageNum() {
nextPageNum = currentPageNum+1;
if(nextPageNum>totalPageNum){
nextPageNum = totalPageNum;
}
return nextPageNum;
}
public int getCurrentPageNum() {
return currentPageNum;
}
public void setCurrentPageNum(int currentPageNum) {
this.currentPageNum = currentPageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalRecords() {
return totalRecords;
}
public void setTotalRecords(int totalRecords) {
this.totalRecords = totalRecords;
}
public int getTotalPageNum() {
return totalPageNum;
}
public void setTotalPageNum(int totalPageNum) {
this.totalPageNum = totalPageNum;
}
public int getStartIndex() {
return startIndex;
}
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
public void setPrePageNum(int prePageNum) {
this.prePageNum = prePageNum;
}
public void setNextPageNum(int nextPageNum) {
this.nextPageNum = nextPageNum;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
}
3、ProductServlet -> findProductsByCidWithPage
获取cid,num
调用业务层功能:以分页形式查询当前类别下商品信息
返回PageModel对象(1_当前页商品信息2_分页3_url)
将PageModel对象放入request
转发到/jsp/product_list.jsp
public String findProductsByCidWithPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取参数(当前页面)
int curPage = Integer.parseInt(request.getParameter("curPage"));
//System.out.println(curPage);
String cid = request.getParameter("cid");
//调用业务层的方法(根据pid查信息)
ProductService service = new ProductServiceImpl();
try {
PageModel page = service.findProductsByCidWithPage(curPage,cid);
//将获取到的商品放入request
request.setAttribute("page", page);
} catch (SQLException e) {
e.printStackTrace();
}
return "/jsp/product_list_COPY.jsp";
}
4、ProductService
创建PageModel对象 目的:计算分页参数
关联集合
关联url
@Override
public PageModel findProductsByCidWithPage(int cpage,String cid) throws SQLException {
int productsNum = dao.getProductsNum(cid);
PageModel page = new PageModel(cpage,productsNum,6);
page.setList(dao.findProductsByCidWithPage(page.getStartIndex(),cid,page.getPageSize()));
page.setUrl("ProductServlet?method=findProductsByCidWithPage&cid="+cid);
return page;
}
5、ProductDao
1_统计当前类别下商品个数
2_统计当前类别的当前页中的商品信息
@Override
public int getProductsNum(String cid) throws SQLException {
String sql = "select count(*) from product where cid = ?";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
Long num = (Long) qr.query(sql, new ScalarHandler(),cid);
return num.intValue();
}
@Override
public List<Product> findProductsByCidWithPage(int num,String cid,int pageNum) throws SQLException {
String sql = "select * from product where cid = ? limit ?,?";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
return qr.query(sql, new BeanListHandler<Product>(Product.class),cid,num,pageNum);
}
6、/jsp/product_list_COPY.jsp
获取分页对象并实现商品分页
<c:if test="${empty page.list}">
<div class="row" style="width:1210px;margin:0 auto;"><h3>暂无商品信息!</h3></div>
</c:if>
<c:if test="${not empty page.list}">
<div class="row" style="width:1210px;margin:0 auto;">
<div class="col-md-12">
<ol class="breadcrumb">
<li><a href="ProductServlet?method=findProductsByCidWithPage&curPage=1">首页</a></li>
</ol>
</div>
<c:forEach items="${page.list }" var="p">
<div class="col-md-2">
<a href="ProductServlet?method=findProductByPid&pid=${p.pid}">
<img src="${pageContext.request.contextPath}/${p.pimage}" width="170" height="170" style="display: inline-block;">
</a>
<p><a href="ProductServlet?method=findProductByPid&pid=${p.pid}" style='color:green'>${p.pname}</a></p>
<p><font color="#FF0000">商城价:¥${p.shop_price}</font></p>
</div>
</c:forEach>
</div>
<!--分页 -->
<div style="width:380px;margin:0 auto;margin-top:50px;">
<ul class="pagination" style="text-align:center; margin-top:10px;">
<c:if test="${page.currentPageNum!=1 }">
<li><a href="${pageContext.request.contextPath}/${page.url}&curPage=${page.prePageNum}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>
</c:if>
<c:forEach begin="1" end="${page.totalPageNum }" var="i">
<c:if test="${page.currentPageNum== i }">
<li><a>${i }</a></li>
</c:if>
<c:if test="${page.currentPageNum!= i }">
<li><a href="${pageContext.request.contextPath}/${page.url}&curPage=${i}">${i }</a></li>
</c:if>
</c:forEach>
<c:if test="${page.currentPageNum!=page.totalPageNum }">
<li>
<a href="${pageContext.request.contextPath}/${page.url}&curPage=${page.nextPageNum}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
</ul>
</div>
</c:if>
约定:1、当前页: curPage 2、向request放入PageModel属性名称page
小结:1、在第二期学习的时候就已经自己实现了商品模块分类的功能,只不过实现的功能没有这么全面而已。我只实现了读取所有商品并分页,而这次还对不同的分类做了商品模块分页的操作。
2、自己实现的与参考的还是有区别的,比如Page对象和PageModel对象,PageModel对象在类中就已经把许多属性在创建对象的时候就可以计算并完成初始化,还多了url、以及其他扩展属性,并不是我一定要改变自己所学的代码,是因为这种封装值得学习,有学习的价值。
3、我自己写的Page对象的属性太少,以至于Service中要额外计算大量的数值,看起来就很繁琐。就好比Servlet中获取到了curPage还要自己判断是不是空值,其实在header.jsp中直接一个参数curPage=1就可以解决了。
4、总的来说就是:对象封装要搞好;Service除了对特定功能的实现最好不要有其他繁杂的东西;代码一定要一次次优化!
3、抽取购物车模型
步骤实现:
1、完成CartItem类对象的书写封装
public class CartItem {
private Product product; //商品信息:包含pid、pimage、pname
private int num = 0; //购买的数量
private double price = 0; //购买该商品的小计
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
price = num*product.getShop_price();
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
2、完成Cart类对象的书写封装
public class Cart {
Map<String, CartItem> products = new HashMap<String, CartItem>();//存放pid和商品信息
double totalPrice; //购物车总计价格
String pid; //商品类别
public void clearCart(){//清空购物车
products.clear();
}
/*添加购物项到购物车
当用户点击加入购物车按钮,可以将当前要购买的商品id,商品数量发送到服务端,服务端根据商品id查询到商品信息
有了商品信息Product对象,有了要购买商品数量,当前的购物项也就可以获取到了*/
public void addCartItem(CartItem cartItem){//添加购物项
pid = cartItem.getProduct().getPid();
if(products.containsKey(pid)){
CartItem old = products.get(pid);
products.get(pid).setNum(old.getNum()+cartItem.getNum());
}else{
products.put(pid, cartItem);
}
}
public void removeCartItem(String pid){//移除购物项
products.remove(pid);
}
//返回MAP中所有的值
public Collection getCartItems(){
return products.values();
}
public double getTotalPrice() {
//totalPrice默认值设置为0
totalPrice = 0;
//获取到Map中所有的购物项
Collection<CartItem> values = products.values();
//遍历所有的购物项,将购物项上的小计相加
for (CartItem cartItem : values) {
totalPrice+=cartItem.getPrice();
}
return totalPrice;
}
public void setTotalPrice(double totalPrice) {
this.totalPrice = totalPrice;
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public Map<String, CartItem> getProducts() {
return products;
}
public void setProducts(Map<String, CartItem> products) {
this.products = products;
}
}
小结:
1、购物模块:购物项+购物车,分开创建类
2、购物车一定要有:(清空购物车、移除购物项、添加购物项、计算总金额)等功能
3、功能实现一定要和实际相结合,根据实际来写,功能就不会少。
4、添加商品到购物车
内存分析:
原理如下:
步骤实现:
1、准备工作
*/jsp/product_list.jsp 修改连接
<a href="${pageContext.request.contextPath}/ProductServlet?method=findProductByPid&pid=${p.pid}">
*/jsp/product_info.jsp
自己设置form表单,设置form method action
设置隐藏域向服务端传递商品pid
<form action="/store_v5/CartServlet?method=addCartItemToCart" method="post">
<div><strong>${product.pname }</strong></div>
<div style="border-bottom: 1px dotted #dddddd;width:350px;margin:10px 0 10px 0;">
<div>编号:${product.pid }</div>
</div>
<div style="margin:10px 0 10px 0;">商城价: <strong style="color:#ef0101;">¥:${product.shop_price}元/份</strong> 市场价: <del>¥${product.market_price}元/份</del>
</div>
<div style="margin:10px 0 10px 0;">促销: <a target="_blank" title="限时抢购 (2020-05-23 ~ 2020-06-01)" style="background-color: #f07373;">限时抢购</a> </div>
<div style="padding:10px;border:1px solid #e7dbb1;width:330px;margin:15px 0 10px 0;;background-color: #fffee6;">
<div style="margin:5px 0 10px 0;">白色</div>
<div style="border-bottom: 1px solid #faeac7;margin-top:20px;padding-left: 10px;">购买数量:
<input id="quantity" name="num" value="1" maxlength="4" size="10" type="text">
<input type="hidden" name="pid" value="${product.pid}">
</div>
<div style="margin:20px 0 10px 0;;text-align: center;">
<%--加入到购物车 --%>
<a href="${pageContext.request.contextPath}/jsp/cart.jsp">
<input style="background: url('${pageContext.request.contextPath}/img/product.gif') no-repeat scroll 0 -600px rgba(0, 0, 0, 0);height:36px;width:127px;" value="加入购物车" type="submit">
</a> 收藏商品</div>
</div>
</form>
PS:如果一个表单中有多个按钮,点击不同的按钮提交到不同路径
var form= document.getElementById(“formId”); form.submit();
2、CartServlet -> addCartItemToCart
(从session获取购物车
如果获取不到,创建购物车对象,放在session中
如果获取到,使用即可)
(获取到商品id,数量
通过商品id查询都商品对象
获取到待购买的购物项)
(调用购物车上的方法
重定向到/jsp/cart.jsp)
//添加购物项到购物车
public String addCartItemToCart(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException {
//从request获取session
HttpSession session = request.getSession();
//从session获取购物车对象,并获取pid与num
Cart cart = (Cart)session.getAttribute("cart");
String pid = request.getParameter("pid");
int num = Integer.parseInt(request.getParameter("num"));
ProductService service = new ProductServiceImpl();
//如果获取不到,创建对象;否则添加商品
if(cart==null) cart = new Cart();
CartItem cartItem = new CartItem();
cartItem.setProduct(service.findProductByPid(pid));
cartItem.setNum(num);
//调用购物车上的方法
cart.addCartItem(cartItem);
//存放对象并重定向到cart.jsp
session.setAttribute("cart", cart);
response.sendRedirect("/store_v5/jsp/cart.jsp");
return null;
}
3、/jsp/cart.jsp 获取购物车上商品信息(直接用c:if和c:foreach来做)
<c:if test="${empty cart.cartItems}">
<div class="row">
<div class="col-md-12"><h3>购物车中暂无商品!</h3></div>
</div>
</c:if>
<c:if test="${not empty cart.cartItems}">
<div class="row">
<div style="margin:0 auto; margin-top:10px;width:950px;">
<strong style="font-size:16px;margin:5px 0;">订单详情</strong>
<table class="table table-bordered">
<tbody>
<tr class="warning">
<th>图片</th>
<th>商品</th>
<th>价格</th>
<th>数量</th>
<th>小计</th>
<th>操作</th>
</tr>
<c:forEach items="${cart.cartItems}" var="item">
<tr class="active">
<td width="60" width="40%">
<input type="hidden" name="pid" value="${item.product.pid }">
<img src="${pageContext.request.contextPath}/${item.product.pimage }" width="70" height="60">
</td>
<td width="30%">
<a target="_blank"> ${item.product.pname }</a>
</td>
<td width="20%">
¥${item.product.shop_price }
</td>
<td width="10%">
<input disabled="disabled" type="text" name="quantity" value="${item.num }" maxlength="4" size="10">
</td>
<td width="15%">
<span class="subtotal">¥${item.price }</span>
</td>
<td>
<a href="javascript:;" class="delete">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
<div style="margin-right:130px;">
<div style="text-align:right;">
<em style="color:#ff6600;">
登录后确认是否享有优惠
</em> 赠送积分: <em style="color:#ff6600;">${cart.totalPrice }</em> 商品金额: <strong style="color:#ff6600;">¥${cart.totalPrice }元</strong>
</div>
<div style="text-align:right;margin-top:10px;margin-bottom:10px;">
<a href="${pageContext.request.contextPath}/jsp/order_info.jsp" id="clear" class="clear">清空购物车</a>
<a href="${pageContext.request.contextPath}/jsp/order_info.jsp">
<%--提交表单 --%>
<input type="submit" width="100" value="提交订单" name="submit" border="0" style="background: url('${pageContext.request.contextPath}/img/register.gif') no-repeat scroll 0 0 rgba(0, 0, 0, 0);
height:35px;width:100px;color:white;">
</a>
</div>
</div>
</c:if>
重定向/转发区别:
1、一次还是两次请求响应 request域数据丢失
2、路径显示问题
3、第二次访问位置
4、重定向一定要加上项目名称,否则报错
5、移除购物车中的购物项
原理如下:
步骤实现:
1、准备工作
在删除购物项的a标签添加id属性
<a href="javascript:;" class="delete" id="${item.product.pid}">删除</a>
为购物车上的删除链接绑定了点击事件
$(function(){
//页面加载完毕之后获取到class的值为delete元素,为其绑定点击事件
$(".delete").click(function(){
if(confirm("确认删除?")){
//获取到被删除商品pid
var pid=this.id;
window.location.href="/store_v5/CartServlet?method=removeCartItem&id="+pid;
}
});
});
2、CartServlet -> removeCartItem
获取待删除商品pid
获取到购物车
调用购物车删除购物项方法
重定向到/jsp/cart.jsp
//移除购物项到购物车
public String delCartItemFromCart(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException {
//从session获取购物车对象,并获取pid
Cart cart = (Cart)request.getSession().getAttribute("cart");
String pid = request.getParameter("pid");
//调用购物车上的方法
cart.removeCartItem(pid);
//重定向到cart.jsp
response.sendRedirect("/store_v5/jsp/cart.jsp");
return null;
}
6、清空购物车
原理如下:
步骤实现:
1、准备工作
/jsp/cart.jsp 修改连接或写script
<a href="${pageContext.request.contextPath}/CartServlet?method=clearCart" id="clear" class="clear">清空购物车</a>
或
<a href="javascript:;" id="clear" class="clear">清空购物车</a>
$(function(){
//页面加载完毕之后获取到class的值为delete元素,为其绑定点击事件
$("#clear").click(function(){
if(confirm("确认清空购物车?")){
window.location.href="/store_v5/CartServlet?method=clearCart";
}
});
});
2、CartServlet -> clearCart
获取购物车
调用购物车的清空方法
重定向到/jsp/cart.jsp页面
//移除购物项到购物车
public String clearCart(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException {
//从session获取购物车对象
Cart cart = (Cart)request.getSession().getAttribute("cart");
//调用购物车上的方法
cart.clearCart();
//重定向到cart.jsp
response.sendRedirect("/store_v5/jsp/cart.jsp");
return null;
}
不积小流,无以成江海~