家居网购项目实现06

以下皆为部分代码,详见 https://github.com/liyuelian/furniture_mall.git

14.功能13-首页分页

14.1需求分析/图解

  1. 顾客进入首页页面
  2. 分页显示家居
  3. 正确显示分页导航条

14.2思路分析

14.3代码实现

14.3.1web层

配置customerFurnServlet

<servlet>
<servlet-name>CustomerFurnServlet</servlet-name>
<servlet-class>com.li.furns.web.CustomerFurnServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CustomerFurnServlet</servlet-name>
<url-pattern>/customerFurnServlet</url-pattern>
</servlet-mapping>

实现servlet

package com.li.furns.web;

import com.li.furns.entity.Furn;
import com.li.furns.entity.Page;
import com.li.furns.service.FurnService;
import com.li.furns.service.impl.FurnServiceImpl;
import com.li.furns.utils.DataUtils; import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException; public class CustomerFurnServlet extends BasicServlet { private FurnService furnService = new FurnServiceImpl(); /**
* 处理首页分页请求
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void page(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//这里的业务逻辑和原先的家居后台分页非常相似
int pageNo = DataUtils.parseInt(req.getParameter("pageNo"), 1);
int pageSize = DataUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);
//调用service方法,获取Page对象
Page<Furn> page = furnService.page(pageNo, pageSize);
//将page放入request域中
req.setAttribute("page", page);
//请求转发到/views/customer/index.jsp - 真正的主页
req.getRequestDispatcher("/views/customer/index.jsp")
.forward(req, resp);
}
}

14.3.2前端页面

1.web/index.jsp

<%--
Created by IntelliJ IDEA.
User: li
Date: 2022/12/21
Time: 17:14
Version: 1.0
--%>
<%-- 直接请求到CustomerFurnServlet,
获取网站首页要显示的分页数据,类似我们的网站入口页面
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--注意这里如果没有子元素的话不要分行!!!--%>
<jsp:forward page="/customerFurnServlet?action=page&pageNo=1"></jsp:forward>

2.web/views/customer/index.jsp

循环标签显示家居信息

<%--循环输出--%>
<c:forEach items="${requestScope.page.items}" var="furn">
<div class="col-lg-3 col-md-6 col-sm-6 col-xs-6 mb-6" data-aos="fade-up"
data-aos-delay="200">
<!-- Single Prodect -->
<div class="product">
<div class="thumb">
<a href="shop-left-sidebar.html" class="image">
<img src="${furn.imgPath}" alt="Product"/>
<img class="hover-image" src="${furn.imgPath}"
alt="Product"/>
</a>
<span class="badges">
<span class="new">New</span>
</span>
<div class="actions">
<a href="#" class="action wishlist" data-link-action="quickview"
title="Quick view" data-bs-toggle="modal"
data-bs-target="#exampleModal"><i
class="icon-size-fullscreen"></i></a>
</div>
<button title="Add To Cart" class=" add-to-cart">Add
To Cart
</button>
</div>
<div class="content">
<h5 class="title">
<a href="shop-left-sidebar.html">${furn.name}</a></h5>
<span class="price">
<span class="new">家居: ${furn.name}</span>
</span>
<span class="price">
<span class="new">厂商: ${furn.maker}</span>
</span>
<span class="price">
<span class="new">价格: ¥${furn.price}</span>
</span>
<span class="price">
<span class="new">销量: ${furn.sales}</span>
</span>
<span class="price">
<span class="new">库存: ${furn.stock}</span>
</span>
</div>
</div>
</div>
</c:forEach>
<%--循环结束--%>

前端导航栏

<ul>
<%--如果当前页大于1,就显示上一页--%>
<c:if test="${requestScope.page.pageNo>1}">
<li><a href="customerFurnServlet?action=page&pageNo=${requestScope.page.pageNo-1}">上页</a></li>
</c:if>
<%-- 显示所有的分页数
先确定开始页数 begin 第一页
再确定结束页数 end 第page.TotalCount页
--%>
<c:set var="begin" value="1"/>
<c:set var="end" value="${requestScope.page.pageTotalCount}"/>
<c:forEach begin="${begin}" end="${end}" var="i">
<%--如果i为当前页,就使用class=active来修饰--%>
<c:if test="${i==requestScope.page.pageNo}">
<li><a class="active" href="customerFurnServlet?action=page&pageNo=${i}">${i}</a></li>
</c:if>
<c:if test="${i!=requestScope.page.pageNo}">
<li><a href="customerFurnServlet?action=page&pageNo=${i}">${i}</a></li>
</c:if>
</c:forEach>
<%-- --%>
<%-- 如果当前页小于总页数,就往下一页--%>
<c:if test="${requestScope.page.pageNo < requestScope.page.pageTotalCount}">
<li><a href="customerFurnServlet?action=page&pageNo=${requestScope.page.pageNo+1}">下页</a></li>
</c:if>
<li><a>共${requestScope.page.pageTotalCount}页</a></li>
<li><a>共${requestScope.page.totalRow}记录</a></li>
</ul>

14.4完成测试

在浏览器访问http://localhost:8080/furniture_mall/,点击分页超链接,可以完成分页显示数据


15.功能14-首页搜索

15.1需求分析/图解

  1. 顾客点击首页搜索框,可以输入家居名
  2. 正确显示分页导航条,并且要求在分页基础上保留上次搜索条件(即点击分页,显示的家居信息仍要符合搜索条件)

15.2思路分析

15.3代码实现

15.3.1dao层

FurnDAO

/**
* 根据furnName返回符合条件的记录数
*
* @param furnName 搜索条件
* @return 返回符合条件的记录数
*/
public int getTotalRowByName(String furnName); /**
* 根据 begin,pageSize,furnName,返回furn的记录
*
* @param furnName 搜索条件
* @return 返回furn对象集合
*/
public List<Furn> getPageItemByName(int begin, int pageSize, String furnName);

FurnDAOImpl

@Override
public int getTotalRowByName(String furnName) {
String sql = "SELECT COUNT(*) " +
"FROM `furn` " +
"WHERE `name` LIKE ?";
return ((Number) queryScalar(sql, "%" + furnName + "%")).intValue();
} @Override
public List<Furn> getPageItemByName(int begin, int pageSize, String furnName) {
String sql = "SELECT `id` , `name` , `maker` , `price` , `sales` , `stock` , `img_path` AS imgPath " +
"FROM `furn` " +
"WHERE `name` LIKE ? LIMIT ?,?";
return queryMulti(sql, Furn.class, "%" + furnName + "%", begin, pageSize);
}

FurnDAOImplTest

@Test
public void getPageTotalCountByName() {
System.out.println("根据名字’沙发‘搜索=>" + furnDAO.getTotalRowByName("沙发"));
} @Test
public void getPageItemByName() {
//从第0条记录开始,每页显示5个记录
List<Furn> furns = furnDAO.getPageItemByName(0, 5, "沙发");
for (Furn furn : furns) {
System.out.println(furn);
}
}


15.3.2service层

FurnService

/**
* 根据传入的pageNo,pageSize和furnName,返回对应的page对象
*
* @param pageNo 表示第几页
* @param pageSize 表示一页取出多少条记录
* @param furnName 搜索的家居名
* @return 返回对应的page对象
*/
public Page<Furn> pageByName(int pageNo, int pageSize, String furnName);

FurnServiceImpl

@Override
public Page<Furn> pageByName(int pageNo, int pageSize, String furnName) {
//先创建一个page对象,然后根据实际情况填充属性
Page<Furn> page = new Page<>();
//1.当前第几页
page.setPageNo(pageNo);
//2.每页取出多少条记录
page.setPageSize(pageSize);
//3.根据名字来返回总记录数
int totalRow = furnDAO.getTotalRowByName(furnName);
page.setTotalRow(totalRow);
//4.总页数 = 总记录数 / 每页记录数
int pageTotalCount = totalRow / pageSize;
if (totalRow % pageSize > 0) {
//如果有余数就把总页数 +1
pageTotalCount++;
}
page.setPageTotalCount(pageTotalCount);
//5.数据集合items
//SELECT * FROM table_name
//LIMIT 每页显示记录数*(第几页-1),每页显示记录数
int begin = (pageNo - 1) * pageSize;
List<Furn> pageItems = furnDAO.getPageItemByName(begin, pageSize, furnName);
page.setItems(pageItems);
//6.还差一个url,分页导航,先放一放
return page;
}

FurnServiceImplTest

@Test
public void pageByName() {
Page<Furn> page = furnService.pageByName(1, 5, "桌子");
for (Furn furn : page.getItems()) {
System.out.println(furn);
}
}

15.3.3web层

CustomerFurnServlet

/**
* 处理首页搜索请求
* 并进行分页(只对搜索到的信息分页)
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void pageByName(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求参数
int pageNo = DataUtils.parseInt(req.getParameter("pageNo"), 1);
int pageSize = DataUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);
//如果参数有name但没有值,接收的就是空串
//如果参数没有name,接收到的就是null
String furnName = req.getParameter("furnName");
//这样做,将""和null的业务逻辑合并在一起
if (furnName == null) {
furnName = "";
}
//调用service方法,获取Page对象
Page<Furn> page = furnService.pageByName(pageNo, pageSize, furnName);
//将page放入request中
req.setAttribute("page", page);
//请求转发到/customer/index.jsp
req.getRequestDispatcher("/views/customer/index.jsp")
.forward(req, resp);
}

15.3.4customer/index.jsp

修改搜索框参数

<form class="action-form" action="customerFurnServlet">
<input type="hidden" name="action" value="pageByName">
<input class="form-control" name="furnName" placeholder="输入家居名搜索" type="text" >
<button class="submit" type="submit"><i class="icon-magnifier"></i></button>
</form>

关于携带上次检索条件,即点击分页,显示的家居信息仍要符合搜索条件:

  1. 功能13-首页分页实现,在导航栏的超链接上附上了请求的servlet路径,servlet中方法以及当前页数等参数。检索信息的分页首页分页 的导航栏,两者功能是相似的,只是在请求的servlet,servlet方法等参数不一致

  2. 检索信息的分页:

    由于furnName的值在搜索栏中提交给CustomerFurnServlet,我们可以在CustomerFurnServlet的pageByName方法中获取到的furnName值,并设置在page的属性url中,返回给jsp页面,这样就可以拿到furnName了

  3. 改进CustomerFurnServlet

    protected void pageByName(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取请求参数
    int pageNo = DataUtils.parseInt(req.getParameter("pageNo"), 1);
    int pageSize = DataUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);
    //如果参数有name但没有值,接收的就是空串
    //如果参数没有name,接收到的就是null
    String furnName = req.getParameter("furnName");
    //这样做,将""和null的业务逻辑合并在一起
    if (furnName == null) {
    furnName = "";
    }
    //调用service方法,获取Page对象
    Page<Furn> page = furnService.pageByName(pageNo, pageSize, furnName);
    //根据furnName
    StringBuilder url = new StringBuilder("customerFurnServlet?action=pageByName");
    if (!"".equals(furnName)) {//如果furnName不为空串,就拼接 furnName参数
    url.append("&furnName=").append(furnName);
    }
    page.setUrl(url.toString());
    //将page放入request中
    req.setAttribute("page", page);
    //请求转发到/customer/index.jsp
    req.getRequestDispatcher("/views/customer/index.jsp")
    .forward(req, resp);
    }
  4. index.jsp的分页导航栏

    <ul>
    <%--如果当前页大于1,就显示上一页--%>
    <c:if test="${requestScope.page.pageNo > 1}">
    <li><a href="${requestScope.page.url}&pageNo=${requestScope.page.pageNo-1}">上页</a></li>
    </c:if>
    <%-- 显示所有的分页数
    先确定开始页数 begin 第一页
    再确定结束页数 end 第page.TotalCount页
    --%>
    <c:set var="begin" value="1"/>
    <c:set var="end" value="${requestScope.page.pageTotalCount}"/>
    <c:forEach begin="${begin}" end="${end}" var="i">
    <%--如果i为当前页,就使用class=active来修饰--%>
    <c:if test="${i==requestScope.page.pageNo}">
    <li><a class="active" href="${requestScope.page.url}&pageNo=${i}">${i}</a></li>
    </c:if>
    <c:if test="${i!=requestScope.page.pageNo}">
    <li><a href="${requestScope.page.url}&pageNo=${i}">${i}</a></li>
    </c:if>
    </c:forEach>
    <%-- --%>
    <%-- 如果当前页小于总页数,就往下一页--%>
    <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotalCount}">
    <li><a href="${requestScope.page.url}&pageNo=${requestScope.page.pageNo+1}">下页</a></li>
    </c:if>
    <li><a>共${requestScope.page.pageTotalCount}页</a></li>
    <li><a>共${requestScope.page.totalRow}记录</a></li>
    </ul>

15.3.5bugFix

上述代码虽然可以解决搜索信息的分页问题,但是如果我们第一次进入首页的时候,走的是CustomerFurnServlet的page方法,因此返回的page的url中是null,如果这时直接点击分页导航栏,就会显示错误,因为获取不到page的url属性,超链接拼接错误。

解决方案:直接将web/index.jsp的action改为pageByName,由于没有给furnName参数,默认搜索的是所有家居信息

15.4完成测试

访问urlhttp://localhost:8080/furniture_mall/,首次进入首页,点击分页导航栏,功能正常

在搜索框中搜索家居名称,成功返回合法数据,点击分页导航栏,功能正常

搜索结果第一页:

搜素结果第三页:

day07-功能实现06的更多相关文章

  1. java io系列01之 "目录"

    java io 系列目录如下: 01. java io系列01之  "目录" 02. java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括 ...

  2. JavaSE_ API常用对象 总目录(11~14)

    JavaSE学习总结第11天_开发工具 & API常用对象111.01 常见开发工具介绍11.02 Eclipse和MyEclipse的概述11.03 Eclipse的下载安装及卸载11.04 ...

  3. 代码审计之XiaoCms(后台任意文件上传至getshell,任意目录删除,会话固定漏洞)

    0x00 前言 这段时间就一直在搞代码审计了.针对自己的审计方法做一下总结,记录一下步骤. 审计没他,基础要牢,思路要清晰,姿势要多且正. 下面是自己审计的步骤,正在逐步调整,寻求效率最高. 0x01 ...

  4. [代码审计]XiaoCms(后台任意文件上传至getshell,任意目录删除,会话固定漏洞)

    0x00 前言 这段时间就一直在搞代码审计了.针对自己的审计方法做一下总结,记录一下步骤. 审计没他,基础要牢,思路要清晰,姿势要多且正. 下面是自己审计的步骤,正在逐步调整,寻求效率最高. 0x01 ...

  5. 20款PHP版WebMail开源项目

    20款PHP版WebMail开源项目 如今互联网巨头提供的企业应用套件中邮件托管是必备服务,而且还始终秉承免费的优良光荣传统,最为让人熟识的恐怕非"瘟多死里屋管理中心"和" ...

  6. Python Flask打造一个视频网站实战视频教程

    下载链接:https://www.yinxiangit.com/607.html 目录: 本套课程从零基础讲解flask开发网站.涉及到的知识点包括:Python和pycharm的安装.urls和视图 ...

  7. 创客课堂——Scratch的操作界面

    大家好,这里是蓝精灵创客公益课堂,我是蓝老师 上期我们了解了scratch软件进行了简单的了解,很多朋友都已经按照上期方法下载安装好了软件. 那么今天蓝老师就和大家一起认识下Scratch的操作界面及 ...

  8. CVE-2012-0774:Adobe Reader TrueType 字体整数溢出漏洞调试分析

    0x01 TrueType 字体 TTF 字体是 Apple 和 Microsoft 两家公司共同推出的字体格式,现在已经广泛的运用于 Windows 操作系统,其中 PDF 文档也可以嵌入 TTF ...

  9. [转载]层叠与并排win10

    三. 层叠与并排 如果要排列的窗口超过4个,分屏就显得有些不够用了,这时不妨试一试最传统的窗口排列法.具体方法是,右击任务栏空白处,然后选择"层叠窗口"."并排显示窗口& ...

  10. Go语言系列之自定义实现日志库

    日志库logo gitee地址传送门:https://gitee.com/zhangyafeii/logo 日志库需求分析 1. 支持往不同的地方输出日志 2. 日志分级别 Debug Trace I ...

随机推荐

  1. Bing 广告平台迁移到 .net6

    原文链接 https://devblogs.microsoft.com/dotnet/bing-ads-campaign-platform-journey-to-dotnet-6/ 广告组件平台对于微 ...

  2. MySQL的日志文件

    本文将重点介绍MySQL的日志文件类型,并讲解其作用,并结合一定实操演示,相信跟着做下来你会对MySQL有更深的理解. 文件的概念 在开始讲MySQL日志文件之前,首先我们要明确一下文件的概念.MyS ...

  3. 路由组件构建方案(分库分表)V1

    路由组件构建方案V1 实现效果:通过注解实现数据分散到不同库不同表的操作. 实现主要以下几部分: 数据源的配置和加载 数据源的动态切换 切点设置以及数据拦截 数据的插入 涉及的知识点: 分库分表相关概 ...

  4. JavaScript基础&实战(5)js中的数组、forEach遍历、Date对象、Math、String对象

    文章目录 1.工厂方法创建对象 1.1 代码块 1.2.测试结果 2.原型对象 2.1 代码 2.2 测试结果 3.toString 3.1 代码 3.2 测试结果 4.数组 4.1 代码 5.字面量 ...

  5. 齐博x1小程序集群必须带上固定的标志

    小程序集群的也类似登录接口一样,需要带上特殊的标志.建议是在所有请求的头部header 加上 wxappid 如下图所示,跟登录标志 token 并列在一起. 如果不方便修改头部header 请求的时 ...

  6. Selenium+Python系列(三) - 常见浏览器操作

    写在前面 上篇文章为大家分享了自动化测试中,常见元素定位的操作. 今天再次读文章,居然忘记了大家特别喜欢的CSS和Xpath定位操作分享,这怎么能行呢? 马上安利,感兴趣的同学去参考下面链接: CSS ...

  7. 9.异步redis

    在使用Python代码操作redis时候,连接.操作.断开都是网络IO #安装支持异步redis的模块 pip3 install aioredis async def execute(address, ...

  8. java中HashMap的设计精妙在哪?

    摘要:本文结合图解和问题,教你一次性搞定HashMap 本文分享自华为云社区<java中HashMap的设计精妙在哪?用图解和几个问题教你一次性搞定HashMap>,作者:breakDaw ...

  9. Win环境安装Protobuf 2.0 版本

    转载请注明出处: 安装步骤 下载 protobuf-2.5.0.zip 与 protoc-2.5.0-win32.zip 下载链接 : https://github.com/protocolbuffe ...

  10. 安装harbor仓库

    1.安装docker-compose curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-c ...