本篇博客,主要内容是增加一个新的功能,内容分类下拉菜单的实现。
目录
三:Controller:增加获取请求中的分类参数,以应对内容分类需求;
零:概述:
按类型查询的功能,需要在Dao层面上对数据进行过滤:
一:Dao:为了应对分类的需求,增加一个重载的方法
PaintingDao类:(1)对pagination方法进行重载;Dao类中根据Category类别对数据进行了处理筛选;(2)很自然,如果请求中有无类别参数,就会分别调用;
package com.imooc.mgallery.dao;
import java.util.ArrayList;
import java.util.List;
import com.imooc.mgallery.entity.Painting;
import com.imooc.mgallery.utils.PageModel;
import com.imooc.mgallery.utils.XmlDataSource;
/**
* Dao类;调用PageModel类和XmlDataSource这个两个工具类;
* 数据访问对象类,作用是获取最原始的xml数据,并且对其进行分页;
* @author dell
*
*/
public class PaintingDao {
/**
* 实现分页的方法
* @param page 查询第几页数据;
* @param rows 每一页显示几条
* @return
*/
public PageModel pagination(int page,int rows) {
List<Painting> xmlDataSourceList = XmlDataSource.getRawData(); // 先获取xml完整的数据;
PageModel pageModel = new PageModel(xmlDataSourceList,page,rows);
return pageModel;
}
/**
* 对pagination方法进行重载
* @param category 类别
* @param page 查询第几页数据
* @param rows 每一页显示几条数据
* @return
*/
public PageModel pagination(int category,int page,int rows) {
List<Painting> xmlDataSourceList = XmlDataSource.getRawData(); // 先获取xml完整的数据;
List<Painting> categoryList = new ArrayList<Painting>(); // 保存符合类别要求的数据
for(Painting p:xmlDataSourceList) {
if(p.getCategory() == category) {
categoryList.add(p);
}
}
PageModel pageModel = new PageModel(categoryList,page,rows);
return pageModel;
}
}
重复一下:PaintingDao类向上提供完整的数据访问对象;Dao除了调用工具类以外,为了满足数据要求,可能会加一些处理数据的代码,将获取的数据进行稍微加工后,再向后传递;即还是那句话,底层工具类只是完成某些模块化的具体功能,而不参与业务逻辑的编写;Dao类调用底层工具类,获取结果后,加上一些业务逻辑代码(如果需要的话)对从工具类获取的数据进行一下加工,然后向上提供完整的数据访问对象!!!
二:Service:利用可变参数,来应对内容分类需求;
(1)利用可选参数来处理;可选参数(本质是一个数组),可选的参数可以出现,可以不出现,可以有1个,也可以有多个;(可以参考:Java方法这篇博客)
package com.imooc.mgallery.service;
import java.util.List;
import com.imooc.mgallery.dao.PaintingDao;
import com.imooc.mgallery.entity.Painting;
import com.imooc.mgallery.utils.PageModel;
/**
* 这个类主要职责:完成的程序业务逻辑;
* 涉及到与底层数据交互的工作,交给Dao类去实现
* @author dell
*
*/
public class PaintingService {
private PaintingDao paintingDao = new PaintingDao();
/**
* 调用PaintingDao类的pagination()方法,获得分页数据;
* 这个类的内容看似和PageModel类的内容雷同,但是这个类还是必须的,在实际的开发中,需要遵从MVC原
* 则的按层逐级调用的规范;;;所以,即便没有其他的业务逻辑,我们也要写一个Service,然后让这个Service去调用Dao;
* @param page 当前第几页
* @param rows 每页有几条数据
* @return 分页对象
*/
public PageModel pagination(int page,int rows,String...category) {
if(rows == 0) { // 可以看到,Service类中不但需要调用Dao来进行数据访问;
// Service类还包括:一些前置条件的检查,以及得到调用结果后的后置数据的处理,这些工作都是与底层数据无关的
// Service类中的方法用于处理完整的业务逻辑,Service类中方法需要尽量写的完整;
// 而Dao中的方法只与底层数据进行交互的;;;
// 所以,在这个例子中,即使Service类中的方法和Dao中的内容基本相同,也必须要要写这个Service类;
throw new RuntimeException("无效的rows参数");
}
if((category.length==0)||(category[0]==null)) { // 如果没有传递可选参数category的时候;
return paintingDao.pagination(page, rows);
}else {
return paintingDao.pagination(Integer.parseInt(category[0]),page, rows);
}
}
}
三:Controller:增加获取请求中的分类参数,以应对内容分类需求;
增加了category参数;
(1)如果请求地址中,附带了类别参数“c”,那么category变量就不是空,自然调用Service的方法的时候,【pagination(int page,int rows,String...category) 】这个可变参数就有值,不会null,Service处理后,就会调用Dao中的【pagination(int category,int page,int rows)】这个重载方法;(2)如果请求地址中,没有附带类别参数“c”,自然category变量就是null,自然调用Service的方法的时候,【pagination(int page,int rows,String...category) 】这个可变参数就是null,Service处理后,就会调用Dao中的【pagination(int page,int rows)】这个重载方法;
package com.imooc.mgallery.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.imooc.mgallery.service.PaintingService;
import com.imooc.mgallery.utils.PageModel;
/**
* Servlet implementation class PaintingController
*/
@WebServlet("/page")
public class PaintingController extends HttpServlet {
private static final long serialVersionUID = 1L;
// 因为在Controller中,需要调用Service,所以这儿先创建PaintingService类的对象;
private PaintingService paintingService = new PaintingService();
/**
* @see HttpServlet#HttpServlet()
*/
public PaintingController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// 1.接受HTTP请求的参数
String page = request.getParameter("p");
String rows = request.getParameter("r");
String category = request.getParameter("c");
if(page == null) { // 如果前台请求的时候没有附带“p”和“r”两个参数,那么page和rows都会是空的,
page = "1"; // 这样下面的paintingService.pagination()会报空指针异常;所以这儿判断处理一下;
} // 如果page或者rows为空,就给其附一个默认值;
if(rows == null) {
rows = "6";
}
// 2.调用Service方法,得到处理结果;
PageModel pageModel = paintingService.pagination(Integer.parseInt(page), Integer.parseInt(rows),category);
// 3.将结果放在当前的请求属性中;
request.setAttribute("pageModel", pageModel); // 这儿的pageModel必须是一个标准的javaBean,这样才能被前台的JSP的el表达式等识别获取
// 4.请求转发至对应的JSP(view视图),进行数据展现;
// 使用请求转发,将当前的请求转发到inde.jsp上;这儿的视图放在了/WEB-INF/jsp目录下;
request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
}
}
四:index.jsp:
对index.jsp修改如下:
<%@page contentType="text/html;charset=utf-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!-- 引入jstl的核心库包 -->
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!-- 引入jstl的格式化包;待会对价格进行 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="css\common.css">
<script type="text/javascript" src="js\js1.js"></script>
</head>
<body>
<c:if test="${param.c != null}">
<c:set var="categoryParam" value="&c=${param.c}"></c:set> <!-- set:在当前页面创建一个变量,保存具体的数据 -->
</c:if>
<c:if test="${param.c == null }">
<c:set var="categoryParam" value=""></c:set>
</c:if>
<div class="header">
<div class="logo">
<img src="image\logo.png">
</div>
<div class="menu" onclick="show_menu()" onmouseleave="show_menu1()">
<div class="menu_title" ><a href="###">内容分类</a></div>
<ul id="title">
<li><a href="/page?c=1">现实主义</a></li>
<li><a href="/page?c=2">抽象主义</a></li>
</ul>
</div>
<div class="auth">
<ul>
<li><a href="#">登录</a></li>
<li><a href="#">注册</a></li>
</ul>
</div>
</div>
<div class="content">
<div class="banner">
<img src="image/welcome.png" class="banner-img">
</div>
<div class="img-content">
<ul>
<c:forEach items="${pageModel.pageData}" var="painting">
<li>
<img src="${painting.preview}" class="img-li">
<div class="info">
<h3>"${painting.pname}"</h3>
<p>
"${painting.description}"
</p>
<div class="img-btn">
<!-- 价格格式化输出 --><!-- 0.00是因为,在实际正式开发,显示价格时必须要在后面增加两位小数.00 -->
<div class="price"><fmt:formatNumber pattern="¥0.00" value="${painting.price}"></fmt:formatNumber></div>
<a href="#" class="cart">
<div class="btn">
<img src="image/cart.svg">
</div>
</a>
</div>
</div>
</li>
</c:forEach>
</ul>
</div>
<div class="page-nav">
<ul>
<li><a href="/page?p=1${categoryParam}">首页</a></li>
<li><a href="/page?p=${pageModel.hasPreviousPage?pageModel.page-1:1 }${categoryParam}">上一页</a></li>
<!-- 步长设为1 -->
<c:forEach begin="1" end="${pageModel.totalPages}" var="pno" step="1">
<li><span ${pno== pageModel.page?"class='first-page'":""}> <!-- el表达式允许使用三目运算符 -->
<!-- 如果c不存在,则href="/page?p=1" -->
<!-- 如果c存在(假设c=2,即抽象主义),则href="/page?p=1&c=2" -->
<a href="/page?p=${pno}${categoryParam}">
${pno}
</a>
</span></li>
</c:forEach>
<li><a href="/page?p=${pageModel.hasNextPage?pageModel.page+1:pageModel.totalPages}${categoryParam}">下一页</a></li>
<li><a href="/page?p=${pageModel.totalPages}${categoryParam}">尾页</a></li>
</ul>
</div>
</div>
<div class="footer">
<p><span>M-GALLARY</span>©2020 POWERED BY IMOOC.INC</p>
</div>
</body>
</html>
几点说明
(1) 给“现实主义”,“抽象主义”增加超链接;
(2)获取请求中的分类参数;
(3)在所有有关分页的地方,请求地址中,添加分类参数;
附加:实现默认主页
主页的地址本来是:【localhost:8080/page】,即每一次都需要输入page才能访问;如何能默认访问【localhost:8080/】就能访问主页?
这样以后,访问【localhost:8080/】而不必加/page就能访问主页了;
这种做法在实际工作中,也是常用的一种策略:即利用默认首页跳转到我们需要的任何地址上!!!