相信很多同学在学习java基础之后,面对各种项目还是相当头疼,那今天我将手把手教你学会JavaWeb项目中的多条件过滤,希望你能在与我实战的过程中积累经验,更进一步。

分页查询

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

数据分析:

通过观察,页面上需要显示下面的几个数据:
当前页: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

@Setter@Getterpublic 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.这里的多个高级查询的参数如何传递?
对于这个问题,我们应该能够比较快的想到解决方案---数据封装,如下:

@Setter@Getterpublic 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中的数据进行显示

看到这,想必你已经清楚多条件过滤的相关内容了,但是这只是众多项目中小小的一环,要想继续提升自己的实战能力,多了解相关信息是很有必要的,如果你对此感兴趣的话,不妨关注我们,我们会发布更多的相关教程,希望能够帮助你在java道路上越走越远。

JavaWeb项目之多条件过滤的更多相关文章

  1. 手把手教你做JavaWeb项目:登录模块

    现如今,无论是客户端还是移动端,无论是游戏登陆还是社交平台登陆,无处不在的“登陆”.那么你知道怎么制作吗?今天就为你娓娓道来: 用户登录 在各大信息管理系统中,登录功能是必不可少的,他的作用就是验证用 ...

  2. Django项目:CRM(客户关系管理系统)--23--15PerfectCRM实现King_admin多条件过滤

    登陆密码设置参考 http://www.cnblogs.com/ujq3/p/8553784.html list_filter = ('source','consultant','consult_co ...

  3. log4j在javaWeb项目中的使用

    在前边的文章中对log4j的配置文件进行了说明,今天介绍如何在普通的javaWeb项目中使用log4j. 在日常的开发过程中,日志使用的很频繁,我们可以利用日志来跟踪程序的错误,程序运行时的输出参数等 ...

  4. (转)一个JavaWeb项目开发总结

    原文地址:http://www.cnblogs.com/lzb1096101803/p/4907775.html 一.学会如何读一个JavaWeb项目源代码 步骤:表结构->web.xml-&g ...

  5. 一个JavaWeb项目开发总结

    一.学会如何读一个JavaWeb项目源代码 步骤:表结构->web.xml->mvc->db->spring ioc->log->代码 先了解项目数据库的表结构,这 ...

  6. javaweb项目-医者天下 (Spring+SpringMVC+MyBatis)

    项目下载地址:http://download.csdn.net/detail/qq_33599520/9826683 项目完整结构图: 项目简介: 医者天下项目是一个基于Spring+SpringMV ...

  7. IDEA新建javaWeb项目

    创建JavaWeb项目的步骤大致如下: 创建JavaWeb项目之前所需要的条件 - 安装jdk - 安装服务器(如:tomcat) - 安装idea 新建项目 New-->Project...

  8. 开发简单的JavaWeb项目

    一.配置相关环境 下载配置JDK,eclipse,Tomcat服务器,Mysql数据库,Navicat for MySQL(数据库可视化工具) 如果你已经做好各个环境的配置,eclipse与Tomca ...

  9. eclipse 使用tomcat运行JavaWeb项目,文件修改后为何不用重启tomcat? (运行web项目的4种方式)探究

                    1.情景说明 在eclipse中,为什么Java文件修改后,重启tomcat class文件才能生效? 为什么jsp修改后,不需重启tomcat就能立即生效? 为什么静 ...

随机推荐

  1. 我TM怎么这么垃圾

    我现在已经完完全全是个废人了 比黄焖鸡还辣鸡 成绩差的一批 其实我一直就不太会学习,也懒不想学习 所以我就越来越辣鸡 再加上最近精神状态不太好 整天呆呆的 我真的是完完全全的一个废人了

  2. UDF——判断边界类型

  3. 20190815网络与信息安全领域专项赛线上赛misc WriteUp

    目录 签到题 题目内容 使用工具 解题步骤 七代目 题目下载地址 使用工具 解题步骤 亚萨西 题目下载链接 使用工具 解题步骤 24word 题目下载链接 使用工具 解题步骤 感想 几星期前报了名却完 ...

  4. 反射调用异常InvocationTargetException和代理类抛出异常

    反射调用方法,如果方法抛出异常,会被包装成InvocationTargetException. 如果反射对象被代理了,在代理类中抛出异常,不会被包装成InvocationTargetException ...

  5. hyper-v显示分辨率如何自动调整

    打开文件/etc/default/grub 找到GRUB_CMDLINE_LINUX_DEFAULT所在行,在最后加上 video=hyperv_fb:[分辨率],比如我想要的分辨率是1600×900 ...

  6. Invalid bound statement (not found) 终极解决办法

    网上已经有很多文章说明可能导致这个报错的原因,无非是以下几种:1.检查xml文件的namespace是否正确 2.Mapper.java的方法在Mapper.xml中没有,然后执行Mapper的方法会 ...

  7. S905系列的uboot分析

    Ubuntu18.04通过PL2303HX连接TTL 接线的连接 PL2303的3.3V悬空, TX接盒子RX, RX接盒子TX, GND接盒子GND 终端选择 系统自带pl2303的驱动, 可以通过 ...

  8. 利用Superlance监控Supervisor运行状态并实现报警

    Superlance是基于supervisor的事件机制实现的一系列命令行的工具集,它实现了许多supervisor本身没有实现的实用的进程监控和管理的特性,包括内存监控,http接口监控,邮件和短信 ...

  9. Python之快速排序代码

    def quicksort(array): less = [] greater = [] if len(array) <= 1: return array pivot = array.pop() ...

  10. vscode配置python之settings.json 智能提示

    vscode编写Python的智能提示,搞了好久,参考了各种网上配置,如下,备份方便自己查找. { "workbench.iconTheme": "material-ic ...