教你用Java web实现多条件过滤功能

生活中,当你闲暇之余浏览资讯的时候,当你搜索资料但繁杂信息夹杂时候,你就会想,如何更为准确的定位需求信息。今天就为你带来:

分页查询

需求分析:在列表页面中,显示指定条数的数据,通过翻页按钮完成首页/上一页/下一页/尾页的查询

数据分析:

通过观察,页面上需要显示下面的几个数据:
当前页:currentPage
页面大小:pageSize
总页数:totalPage
首页:1
上一页:prevPage
下一页:nextPage
尾页:endPage
总条数:totalCount
结果集:result

那么,我们应该如何方便快速的将这多个数据共享到页面上呢?答案是:封装

我们应该将这几个参数封装到一个对象中,然后共享这个对象即可,所以,我们有了下面这个类

@Getterpublic class PageResult {

public static final  PageResult EMPTY_RESULT = new PageResult(Collections.EMPTY_LIST, 0, 1, 3);

//1:两传

private int currentPage;

private int pageSize;

//2:两查

private List<?> result;

private int totalCount;

//3:三计算

private int prevPage;

private int nextPage;

private int endPage;

public PageResult(List<?> result, int totalCount, int currentPage, int pageSize){

this.result = result;

this.totalCount = totalCount;

this.pageSize = pageSize;

this.currentPage = currentPage;

//计算

this.endPage = totalCount % pageSize == 0 ?

totalCount / pageSize : totalCount / pageSize  + 1;

this.prevPage = currentPage - 1 > 0 ? currentPage - 1 : 1;

this.nextPage = currentPage + 1 > endPage ? endPage :currentPage + 1;

}

}

在这个类中,我们提供了一个构造器来快速封装数据
其中,endPage/prevPage/nextPage是通过上面的几个参数计算得来的

在这些数据中,存在两个需要从数据库中查询得到的数据:总条数/结果集
这两个数据我们需要下面两条SQL进行查询

查询部门表中数据的总条数

SELECT count(id) FROM department

使用LIMIT关键字查询指定页面的数据

SELECT  id, name, sn FROM department LIMIT #{start}, #{pageSize}

#{start}:         使用(currentPage-1)*pageSize表达式计算出来的开始索引#{pageSize}: 每次查询的最大条数

要执行这两条SQL,需要用户传递两个参数:currentPage和pageSize
为了参数方便传递,我们将这两个参数封装到一个类中:QueryObject

@[email protected] class QueryObject {

// 默认查询第一页的数据

private int currentPage = 1;

// 页面中默认显示10条数据

private int pageSize = 5;

public int getStart(){

return (currentPage - 1)*pageSize;

}

}

可以看出,查询结果集中的#{start}表达式,是访问查询对象中的getStart()方法来获取到计算得到的开始索引

到此,我们都已经封装好了分页查询中最核心的两个类:
QueryObject:封装用户传递过来的currentPage/pageSize
PageResult:封装页面上显示需要的result/totalCount/currentPage/pageSize/totalPage/prevPage/pageSize

有了这两个类,我们就可以在service中定义下面的方法,来处理分页查询的业务了:

public PageResult query(QueryObject qo) {

//查询表中数据的总条数

int totalCount = dao.queryForCount(qo);

//当查询到的总条数为0时,说明没有数据,此时就不应该再之后下面的查询

//直接返回相应的默认值即可

if (totalCount == 0) {

return PageResult.EMPTY_RESULT;

}

List<Department> data = dao.queryForList(qo);

PageResult result = new PageResult(data, totalCount, qo.getCurrentPage(), qo.getPageSize());

return result;

}

该方法接收用户传递的数据(QueryObject),返回用户需要的数据(PageResult)
通过调用dao中的两个方法执行两条SQL查询数据(总条数和结果集)

<!--查询总条数--><select id="queryForCount" resultType="java.lang.Integer">

SELECT count(id)

FROM department

</select><!--查询结果集-->

<select id="queryForList" resultType="Department">

SELECT

id,

name,

sn

FROM department

LIMIT #{start}, #{pageSize}

</select>

然后将数据封装到PageResult对象中返回给表现层

表现层获取到service中封装的PageResult对象后,共享到request作用域中
然后请求转发到list.jsp页面

protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//接收用户传递的currentPage和pageSize

String currentPage = req.getParameter("currentPage");

String pageSize = req.getParameter("pageSize");

//将数据封装到QueryObject中,传递给service进行处理

QueryObject qo = new QueryObject();

if(!StringUtils.isNullOrEmpty(currentPage)){

qo.setCurrentPage(Integer.valueOf(currentPage));

}

if(!StringUtils.isNullOrEmpty(pageSize)){

qo.setPageSize(Integer.valueOf(pageSize));

}

PageResult result = service.query(qo);

//共享获取到的PageResult对象

req.setAttribute("result", result);

req.setAttribute("qo", qo);

//请求转发回到list.jsp页面

req.getRequestDispatcher("/WEB-INF/views/department/list.jsp").forward(req, resp);

}

在list.jsp页面上,使用EL+JSTL获取数据并显示在对应的位置
部门列表

<c:forEach items="${result.data}" var="entity" varStatus="vs">

<tr>

<td>${vs.count}</td>

<td>${entity.name}</td>

<td>${entity.sn}</td>

<td>

<a class="btn btn-info btn-xs" href="/department?cmd=input&id=${entity.id}">

<span class="glyphicon glyphicon-pencil"></span>编辑

</a>

<a href="/department?cmd=delete&id=${entity.id}" class="btn btn-danger btn-xs">

<span class="glyphicon glyphicon-trash"></span>删除

</a>

</td>

</tr></c:forEach>

分页条

<div style="text-align: center;">

<a href="javascript:;" onclick="goPage(1)">首页</a>

<a href="javascript:;" onclick="goPage(${result.prevPage})">上一页</a>

<a href="javascript:;" onclick="goPage(${result.nextPage})">下一页</a>

<a href="javascript:;" onclick="goPage(${result.endPage})">尾页</a>

当前页: ${result.currentPage} / ${result.endPage}

跳转到第: <input id="currentPage" name="currentPage" style="width: 80px; text-align: center;"

type="number" min="1" max="${result.endPage}" value="${result.currentPage}"/> 页

<input type="submit" value="GO"/>

每页显示:

<select name="pageSize" onchange="goPage(1);">

<option ${qo.pageSize==5?"selected=‘selected‘":""}>5</option>

<option ${qo.pageSize==10?"selected=‘selected‘":""}>10</option>

<option ${qo.pageSize==15?"selected=‘selected‘":""}>15</option>

<option ${qo.pageSize==20?"selected=‘selected‘":""}>20</option>

</select>

条</div>

效果如下

说明:
在点击翻页的时候,通过执行相应的JS代码提交表单来发起请求
将需要查询的当前页的值设值给表单中的id为currentPage的输入框,然后提交表单
目的主要是和后面的高级查询进行合并使用

做到这里,我们部门的分页功能就完成了
因为部门的字段比较少,所以,在这个模块中,没有设计高级查询的功能,这个功能我们在员工模块中再去实现
接下来,我们来看看员工模块相应功能的实现

在完成部门的CRUD和分页查询后发现,其他模块的这些功能基本相似
不同之处主要在于字段不同而已,所以,在这里,我们主要对这些不同点进行说明,其他的按照前面的实现即可

首先,来看看员工的表结构

在该表中,前六个字段都是基本的字段,第七个(dept_id),这个字段是关联部门的外键列
所以,待会儿我们在完成CRUD的过程中,需要注意维护该字段的值

清楚表结构之后,我们来对员工的CRUD做一个简单的分析

查询功能:

可以看到,处理部门这一列显示的数据比较特殊之外,其他的都是基本的数据展示而已
什么是特殊?什么是不特殊?
员工除了部门的信息外,其他的数据都是直接来自于数据库,而部门在表中只存储了对应的编号,但是页面上需要显示部门的名称,那么这个问题我们是怎么解决的呢?

好,首先解释一下,这个问题的解决方案在目前我们的web阶段还没有涉及过,所以,我在这只能点到为止

我们的解决方案是:在执行该数据的查询的时候,使用多表查询,将员工及其所在部门的信息查询出来,SQL如下:

SELECT

e.id,

e.name,

e.password,

e.email,

e.age,

e.admin,

e.dept_id,

d.id   d_id,

d.name d_name,

d.sn   d_sn

FROM employee e LEFT JOIN department d on e.dept_id = d.idlimit #{start}, #{pageSize}

这条SQL能够查询到如下的结果

然后在resultMap中如下的配置,完成数据的封装,员工相关的数据封装到Employee对象中,部门相关的数据封装到Department对象中

<resultMap id="BaseResultMap" type="Employee">

<id column="id" jdbcType="BIGINT" property="id"/>

<result column="name" jdbcType="VARCHAR" property="name"/>

<result column="password" jdbcType="VARCHAR" property="password"/>

<result column="email" jdbcType="VARCHAR" property="email"/>

<result column="age" jdbcType="INTEGER" property="age"/>

<result column="admin" jdbcType="BIT" property="admin"/>

<!-- 一对多关系 -->

<association property="dept" javaType="Department">

<id column="d_id" property="id"/>

<result column="d_name" property="name"/>

<result column="d_sn" property="sn"/>

</association>

</resultMap>

最后,在select元素中使用resultMap来完成映射

<select id="queryForList" resultMap="BaseResultMap">

完成这些操作之后,我们获取到的每个员工及其所在的部门信息就封装好了,那么,在JSP页面中使用EL表达式,就能够获取到当前员工所在部门的相关信息了

<td>${entity.dept.name}</td>

查询功能分析到此结束,其他功能和部门的一致

新增功能:

需求分析:
保存用户的相关信息,包括用户所在部门的信息
通过对员工表的观察发现,表中关联了部门的主键信息,来说明当前员工所在的部门
所以,在保存员工的时候,需要为员工设置所在的部门.页面设计如下

为员工设置所在的部门,用户只需要进行选择即可,然后将选中部门的id传递到服务端
那么问题来了,如何将部门id通过下拉框传递到服务端呢?请看下面的分析

protected void input(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

List<Department> departments = departmentService.list();

req.setAttribute("departments", departments);

String id = req.getParameter("id");

if (!StringUtils.isNullOrEmpty(id)) {

Employee employee = service.get(Long.valueOf(id));

req.setAttribute("employee", employee);

}

req.getRequestDispatcher("/WEB-INF/views/employee/input.jsp").forward(req, resp);

}

<select class="form-control" id="dept" name="deptId">

<c:forEach var="d" items="${departments}">

<option value="${d.id}" >${d.name}</option>

</c:forEach>

</select>

首先,在跳转到该页面之间,我们先将所有的部门信息查询到
然后在页面上循环遍历,生成对应的option元素,将部门的id作为option的value(提交的数据),将部门的name作为option的文本内容(显示的数据)
最后,在用户选择对应选项后,提交表单,会将对应option元素的value提交到后台,完整数据如下:

通过上图,可以清晰的看到,我们已经将完整的数据提交到后台
后台获取到这些数据之后,就能够将其保存到数据库中
那么,我们的保存功能就算完成了

更新功能:

更新和保存只有一个地方不同,就是需要数据回显
而数据回显中,我们只对部门(下拉框)和超级管理员(复选框)做一个说明,其他的因为都是普通的input元素,使用value属性显示数据即可
而下拉框和复选框需要单独进行处理,如下:

<select class="form-control" id="dept" name="deptId">

<c:forEach var="d" items="${departments}">

<option value="${d.id}" ${employee.dept.id==d.id?"selected":""}>${d.name}</option>

</c:forEach></select>

<input type="checkbox" id="admin" name="admin" ${employee.admin?‘checked‘:‘‘}>

这里,我们选择使用EL表达式的三元运算符进行判断,为下拉框添加selected属性,为复选框添加checked属性

编辑的时候,数据能回显,接下来的操作和新增一致

删除功能

和部门的删除一致,这里就不再赘述

到此,员工的CRUD结束

高级查询

功能需求:
输入关键字和部门信息进去过滤查询,关键字是根据姓名和邮箱两个字段查询

页面设计

高级查询效果图

当用户输入关键字"赵"和部门"总经办"后,在列表中显示的查询结果则为所有总经办姓赵的员工

那么此时应该执行下面的SQL来查询相应的数据

SELECT

e.id, e.name, e.password, e.email, e.age, e.admin, e.dept_id, d.id d_id, d.name d_name, d.sn d_sn

from

employee e

LEFT JOIN

department d

ON

e.dept_id = d.id

WHERE

(e.name LIKE concat(‘%‘,? ,‘%‘) OR e.email LIKE concat(‘%‘,? ,‘%‘)) AND e.dept_id = ? LIMIT ?, ?

在该SQL中,WHERE后面的条件是根据用户传递的高级查询相关的参数拼接而来

这里,我们需要解决两个问题:
1.这里的多个高级查询的参数如何传递?
对于这个问题,我们应该能够比较快的想到解决方案---数据封装,如下:

@[email protected] class EmployeeQueryObject extends QueryObject {

private String keyword;  //按照员工名称与邮箱模糊查询

private Long deptId = -1L;  //按照部门id查询

//当keyword为null或者空字符串的时候,都视为null处理

public String getKeyword(){

return StringUtils.isEmpty(keyword) ? null : keyword;

}

}

2.参数拿到后,如何拼接到对应的SQL中?
使用mybatis中的动态SQL中提供的标签,在mapper映射文件中进行SQL的拼接

<sql id="base_where">

<where>

<if test="keyword != null">

AND( e.name LIKE concat(‘%‘,#{keyword} ,‘%‘) OR e.email LIKE concat(‘%‘,#{keyword} ,‘%‘))

</if>

<if test="deptId > 0">

AND e.dept_id = #{deptId}

</if>

</where>

</sql>

以上两个问题解决后,我们就可以根据用户传递过来的参数,执行对应的过滤查询的SQL
最后,和分页查询的逻辑一样,将数据封装到PageResult中,和分页相关的数据一同返回到页面
效果如[高级查询效果图]所示

好了,基本功能是完成了,我们再来看看下面的问题:
首先,在表单中输入下面的参数,然后查询

然后点击下一页进行翻页

可以看到,在点击翻页之后,我们不是在上面的基础上查询下一页的数据,而是查询到了所有的数据,WHY?
其实很简单,来看看我们的请求参数,一切就清楚了
在我们点击翻页的时候,传递的参数只有currentPage,并没有将之前的高级查询的参数一起传递到后台,所以执行了下面的SQL查询到上面的结果

SELECT

e.id, e.name, e.password, e.email, e.age, e.admin, e.dept_id, d.id d_id, d.name d_name, d.sn d_sn

from

employee e

LEFT JOIN

department d

on

e.dept_id = d.id limit ?, ?

所以,要想在之前高级查询的基础上,继续进行分页查询,那么我们只有一个办法,就是在翻页的时候将高级查询和分页的参数一起提交到后台,拼接执行相应的SQL才行

解决方案:
使用JS来完成数据的提交(JS在目前阶段还未进行系统学习,所以,这里大家重点应该是放在我们要做的事情上,而不是怎么做)

<script type="text/javascript">

function goPage(currentPage) {

//为表单中的currentPage输入框设值

document.getElementById("currentPage").value = currentPage

//提交表单

document.forms[0].submit();

}

</script>

翻页条

<a href="javascript:;" onclick="goPage(1)">首页</a>

<a href="javascript:;" onclick="goPage(${result.prevPage})">上一页</a

<a href="javascript:;" onclick="goPage(${result.nextPage})">下一页</a

<a href="javascript:;" onclick="goPage(${result.endPage})">尾页</a>

在点击翻页按钮时,调用定义好的goPage函数,完成其中的两件事即可
此时,我们可以看到问题已然解决

最后,页面跳转和页面大小的设置功能,我们不做要求,如果要实现也很简单,我这里就直接把相关代码贴出来

跳转到第: <input id="currentPage" name="currentPage" style="width: 80px; text-align: center;"

type="number" min="1" max="${result.endPage}" value="${result.currentPage}"/> 页<input type="submit" value="GO"/>

每页显示:<select name="pageSize" onchange="goPage(1);">

<option ${qo.pageSize==5?"selected=‘selected‘":""}>5</option>

<option ${qo.pageSize==10?"selected=‘selected‘":""}>10</option>

<option ${qo.pageSize==15?"selected=‘selected‘":""}>15</option>

<option ${qo.pageSize==20?"selected=‘selected‘":""}>20</option></select>

好了,高级查询的功能实现到此结束,我们来做一个小结
高级查询和分页的功能,我们应该重点分析两个点
1.用户需要看到什么数据?
2.这些数据应该执行什么样的SQL才能查询到?
如果将这两个问题分析清楚了,那么大家就能够知道这个过程中所封装的几个类的作用了
QueryObject:封装查询对象中通用的属性
EmployeeQueryObject:封装高级查询相关的条件参数
PageResult:封装用户需要使用到的数据

所以实现步骤大致如下:
1.获取到用户传递的高级查询和分页的参数,封装到对象的查询对象中
2.从查询对象中取出数据,然后拼接SQL
3.将查询之后得到的结果,封装到PageResult对象中
4.页面获取到PageResult中的数据进行显示

读到这里,你肯定对多条件过滤功能有所了解呢?或者说知道该如何去实现这个功能了?如果有不明白的地方也可以通过留言或者私信。

原文地址:https://www.cnblogs.com/chenmo2580/p/11960669.html

时间: 2024-10-13 04:45:00

教你用Java web实现多条件过滤功能的相关文章

Java实现文本文件按条件过滤的简便方法

程序开发中经常会碰到处理文本文件中数据的情况,这里通过一个例子来看用java实现文本文件按条件过滤的方法:从文本文件employee.txt中读取员工信息,从中找出1981年1月1日(含)之后出生的女员工. 文本文件empolyee.txt的格式如下: EID   NAME       SURNAME        GENDER  STATE        BIRTHDAY        HIREDATE         DEPT         SALARY 1       Rebecca  

java web开发 图片上传功能

基本思路在于,配置路径,然后用java I/O的api将图片上传到该目录下. String photoPath =    ServletActionContext.getServletContext().getRealPath("/user/photo/" + username); 这句是获取服务器下的目录+username 而username通过session获取. 这是一个图片上传action的方法: public String execute() throws Exception

hibernate使用@where实现条件过滤功能

编程中最常用的功能,增删改查,而实际业务中真正物理删除数据的情况是很少的,基本都有使用逻辑删除,通常采用一个标志位,比如flag,查询的时候,flag=1的数据查出,flag=0的数据过滤掉. 使用hibernate的时候,通常不再直接才做sql语句,而是操作实体和HQL相结合的方式,只要维护好实体之间的关系,增删改查都可以使用极其简单的方式来完成,哪怕关联了好多张表好多个实体. 逻辑删除的时候就是更新一张表,那也只需要维护实体的一个标志位就可以了,不需要写HQL语句,如果要把主表和从表里的标志

【java项目实战】一步步教你使用MyEclipse搭建java Web项目开发环境(一)

首先,在开始搭建MyEclipse的开发环境之前,还有三步工具的安装需要完成,只要在安装配置成功之后才可以进入下面的java Web项目开发环境的搭建. 1.安装工具 第一步,下载并安装JDK,到官网上下载安装即可,之后需要细心的配置环境变量,我给大家推荐百度文库的一篇文章,猛戳这里. 第二步,下载Tomcat,当然可以去Apache Tomcat的官网,同样,您可以移驾到我的资源下载,外送API文档(免资源分). 第三步,下载MyEclipse,MyEclipse官网,傻瓜式安装即可. ===

自我总结(四) ---java web项目完结,j2ee的开始

自我完善的过程就是在不断的自我总结不断的改进. 前半个月刚好把项目做完了,项目也答辩了.总的来说吧,我觉得自己在java web这块知识上不算是彻彻底底把他弄懂了,就是说到的知识点都能够回答的上来一些.因为在答辩之前做了一些工作嘛!答辩成绩还好!其实刚开始做这个项目病虫害防治系统的时候,我觉得我一个人应该是做不完的.虽然表面上我说我会做完的,最后呢还是有一些功能没有去完善它,只是简单的去处理了一下.(对于信息的验证,我就全部一起验证,就没有一个一个的去验证.还有就是在管理员登陆的时候有个权限,这

Java Web的数据库操作(一)

一.JDBC技术 1.JDBC简介 JDBC是Java程序与数据库系统通信的标准API,它定义在JDK的API中,通过JDBC技术,Java程序可以非常方便地与各种数据库交互,JDBC在Java程序与数据库系统之间假期了一座桥梁. JDBC由一组用Java语言编写的类和接口组成,它对数据库的操作提供了基本方法,但由于数据库种类跟多且多有不同,所以对数据库的细节操作由数据库厂商进行实现,且厂商需要提供数据库的驱动程序,下图为Java程序与数据库相交互的示意图: 2.JDBC连接数据库的过程 l 

Docker搭建Java Web运行环境

1. 前提条件 安装了Docker的64位Linux 操作系统 Linux操作系统镜像 Linux版本的JDK压缩包 Linux版本的Tomcat压缩包 2. 启动容器 容器是在镜像的基础上来运行的,一旦容器启动了,我们就可以登录到容器中,安装自己所需的软件或应用程序. 启动命令:(docker run <相关参数> <镜像 ID> <初始命令>) docker run -i -t -v /root/software/:/mnt/software/ 25c5298b1a

Java Web架构知识整理——记一次阿里面试经历

惭愧,从一次电面说起.我个人在某国企做一名软件设计师,国企大家都懂的,待遇一般而且没啥意思,做的方向基本都是操作系统.驱动和工具软件的开发,语言基本都是C/C++.最近也想跳槽,刚好有幸得到了一次阿里的面试机会,于是就试了试. 首先是电话面试,当时正在上班,人多口杂,好不容易找了个没人的地方开始面试.面试的方向是Java Web,面试官很nice,跟朋友一样,一开始问了些比较基础的东西,比如hashmap/hashtable的区别和优缺点,我答得还行,而且对于原理的东西还算讲的比较透彻. Jav

Java Web 项目优化

个人总结的Java Web 的注意事项 1.禁止在循环中,出现操作数据库的操作. 原因是:操作数据库打开和关闭耗费时间内存       例如:  尽量避免不要在程序中出现如下这样操作                for(Object o:entitys){                   save(o);                  update(o); delete(o); // } 2.在程序出现的HQL或者SQL语句,尽可能把先能过滤数据多的条件放在第一位         3.