分页和过滤查询
流程图 :
高级查询.jpg1 设计和原理分析
image-20200521230058307.png
前面我们已经讲过分页查询了 , 接下来我们讲讲 过滤查询 .
思路 : 从后台开始写 , 写好测试 , 测试成功 ; 开始写前台 .
这里我们需要 MyBatis动态sql语句
为了解决在 xml 中拼接 SQL 的问题,此处需要来学习 MyBatis 的动态 SQL
<where> 和<if> 标签的配合使用
<select id="queryCount" resultType="int">
SELECT count(*) FROM t_armoire
<where>
<if test="keyword!=null and keyword!=''">
AND supplier LIKE concat('%',#{keyword},'%')
</if>
<if test="minPrice!=null">
AND price >= #{minPrice}
</if>
<if test="maxPrice!=null">
AND price <= #{maxPrice}
</if>
</where>
</select>
<select id="queryResult" resultType="armoire">
SELECT * FROM t_armoire
<where>
<if test="keyword!=null and keyword!=''">
AND supplier LIKE concat('%',#{keyword},'%')
</if>
<if test="minPrice!=null">
AND price >= #{minPrice}
</if>
<if test="maxPrice!=null">
AND price <= #{maxPrice}
</if>
</where>
limit #{beginIndex},#{pageSize}
</select>
首先 , 我们现在需要用户传入的 过滤条件封装成对象 ArmoireQueryObject, 去继承 QueryObject ,这样我们通过 ArmoireQueryObject就可以获取用户传来的所有参数 .
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class ArmoireQueryObject extends QueryObject {
//用户传来 高级查询 的参数
//1. 关键字 2. 最小值 3. 最大值
private String keyword;
private Integer minPrice;
private Integer maxPrice;
//继承 这样 其实已经有 5+2 + getBegin 数据了
}
list.jsp 操作步骤 添加在 form标签中
<p align="center"> //这里是value 是回显,可以先不管
关键字:<input type="text" name="keyword" value="${aq.keyword}">
价格:<input type="number" name="minPrice" value="${aq.minPrice}"> ~ <input type="number" name="maxPrice" value="${aq.maxPrice}">
<input type="submit" value="提交"></p>
注意:一般的,为了避免不必要的麻烦,让字段名称和表单中的请求参数名称相同 .
DAO
public interface IArmoireDAO {
//高级查询 总条数
int queryCount(ArmoireQueryObject aq);
//高级查询 页面结果集
List<?>queryResult(ArmoireQueryObject aq);
}
public class ArmoireDAOImpl implements IArmoireDAO {
@Override
public int queryCount(ArmoireQueryObject aq) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int count = sqlSession.selectOne("cn.wolfcode.amis.mapper.ArmoireMapper.queryCount", aq);
sqlSession.close();
return count;
}
@Override
public List<?> queryResult(ArmoireQueryObject aq) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
List<?>list = sqlSession.selectList("cn.wolfcode.amis.mapper.ArmoireMapper.queryResult", aq);
sqlSession.close();
return list;
}
}
注意 ; MyBatisUtil 自己去拿 . 算了 还是写给你吧 (这是我封装好的工具类 , 拿去用吧 害 !)
public class MyBatisUtil {
private MyBatisUtil() {
//私有化构造器
}
static SqlSessionFactory factory = null;
static {
try {
factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return factory.openSession();
}
}
还有后面 service要用的工具类 , 方便点 , 统统给你. StringUtil
public class StringUtil {
private StringUtil(){
//私有化构造器
}
//判空
public static boolean hasLength(String str){
return str!=null && !"".equals(str.trim());
}
}
后台这样其实就已经写好了 , 测试下吧 . 成功继续...
想想我们 需要给前台 返回什么数据 ??? 之前分页查询已经说过了 .
两输 , 两查 , 三计算 封装成对象 .
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class PageResult {
//存 2输 2查 3计算
private int currentPage;
private int pageSize;
//2查
private int totalCount;
private List<?> listResult;
//3 计算 上一页 下一页 总页数
private int totalPage;
private int prevPage;
private int nextPage;
//自定义构造器
public PageResult(int currentPage,int pageSize,int totalCount,List<?> listResult){
this.currentPage=currentPage;
this.pageSize=pageSize;
this.totalCount=totalCount;
this.listResult=listResult;
this.totalPage=totalCount%pageSize==0?totalCount/pageSize:totalCount/pageSize+1;
this.prevPage=currentPage>1?currentPage-1:1;
this.nextPage=currentPage<totalPage?currentPage+1:totalPage;
}
}
我们看看service 层 (调用方法: 参数: 前台的数据传来封装到 ArmoireQueryObject 对象中)返回一个前台需要的 所有数据 PageResult对象过去 .
public interface IArmoireService {
//业务层
PageResult query(ArmoireQueryObject aq);
}
简单吧 ! ! !
有了接口 , 就要去实现吧 , 不然要它何用 ?
实现 :
public class ArmoireServiceImpl implements IArmoireService {
@Override
public PageResult query(ArmoireQueryObject aq) {
IArmoireDAO dao=new ArmoireDAOImpl();
List<?> list = dao.queryResult(aq);
int count = dao.queryCount(aq);
if(count==0){
//如果为0 , 返回空集
return new PageResult(aq.getCurrentPage(),aq.getPageSize(),0,new ArrayList<>());
}
return new PageResult(aq.getCurrentPage(),aq.getPageSize(),count,list);
}
}
真棒 , 都看到这里了 , 那我们是不是应该做啥事呢 ? 肯定是测试呀 !(还用想吗, 一天天的啥也不是啊哈! ! !)
测试成功 ...
我们开始写 servlet吧 快结束了 .
@WebServlet("/arm")
public class ArmoireServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
IArmoireService service=new ArmoireServiceImpl();
ArmoireQueryObject aq = new ArmoireQueryObject();
//分页查询 : 用户输入
String strCurrentPage = req.getParameter("currentPage");
if(StringUtil.hasLength(strCurrentPage)){
Integer currentPage = Integer.valueOf(strCurrentPage);
aq.setCurrentPage(currentPage);
}
String strPageSize = req.getParameter("pageSize");
if(StringUtil.hasLength(strPageSize)){
Integer pageSize = Integer.valueOf(strPageSize);
aq.setPageSize(pageSize);
}
//过滤查询
String keyword = req.getParameter("keyword");
aq.setKeyword(keyword);
String strMinPrice = req.getParameter("minPrice");
if(StringUtil.hasLength(strMinPrice)){
Integer minPrice = Integer.valueOf(strMinPrice);
aq.setMinPrice(minPrice);
}
String strMaxPrice = req.getParameter("maxPrice");
if(StringUtil.hasLength(strMaxPrice)){
Integer maxPrice = Integer.valueOf(strMaxPrice);
aq.setMaxPrice(maxPrice);
}
PageResult list = service.query(aq);
//共享
req.setAttribute("aq",aq);//回显数据 这里有 关键字 最大 最小 +2
req.setAttribute("list",list);//返回 页面需要的 结果数据
//跳转
req.getRequestDispatcher("/list.jsp").forward(req,resp);
}
}
总算写好了 , 那我们要干啥啊 , 问我 ? ? ? 把它装上 jsp页面上 .
看着有点复杂 , 其实静下心来 , 看看 , 其实 JAVA 也就那样 . 其实 学习 JAVA 也是一种修行哈 , 越努力越幸运 , 加油 !
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>信息管理系统</title>
<script>
function onChange() {
document.forms[0].submit();
}
function goPage(pageNum) {
document.getElementById("currentPageId").value = pageNum;
document.forms[0].submit();
}
</script>
</head>
<body>
<h3 align="center">货品信息查询系统</h3>
<form action="/arm">
<p align="center">
关键字:<input type="text" name="keyword" value="${aq.keyword}">
价格:<input type="number" name="minPrice" value="${aq.minPrice}"> ~ <input type="number" name="maxPrice" value="${aq.maxPrice}">
<input type="submit" value="提交"></p>
<table border="1" cellpadding="0" cellspacing="0" style="width: 80%" align="center">
<tr>
<th>序号</th>
<th>出产商</th>
<th>类型</th>
<th>价格</th>
</tr>
<c:forEach items="${list.listResult}" var="arm" varStatus="vs">
<tr>
<td>${vs.count}</td>
<td>${arm.supplier}</td>
<td>${arm.type}</td>
<td>${arm.price}</td>
</tr>
</c:forEach>
<tr align="center">
<td colspan="4">
<a href="#" onclick="goPage(1)">首页</a>
<a href="#" onclick="goPage(${list.prevPage})">上一页</a>
<a href="#" onclick="goPage(${list.nextPage})">下一页</a>
<a href="#" onclick="goPage(${list.totalPage})">末页</a>
当前${list.currentPage}页
共${list.totalPage}页
跳转<input type="number" name="currentPage" onchange="onChange()" style="width: 60px"
value="${list.currentPage}" id="currentPageId">页
每页显示
<select name="pageSize">
<option value="3" ${list.pageSize==3?'selected':''}> 3</option>
<option value="5" ${list.pageSize==5?'selected':''}> 5</option>
<option value="8" ${list.pageSize==8?'selected':''}> 8</option>
</select>
条数据
</td>
</tr>
</table>
</form>
</body>
</html>
网友评论