多條件過濾引發(fā)的那些小小疑慮

對于希望將java作為畢生事業(yè)的來說,掌握java基礎(chǔ)知識是遠(yuǎn)遠(yuǎn)不夠的,還需要在各種實戰(zhàn)項目中提升能力,JavaWeb項目實戰(zhàn)的重要性不言而喻,接下來,我就為你分享一下關(guān)于JavaWeb項目中多條件過濾相關(guān)的內(nèi)容,希望可以幫到你。

成都創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于做網(wǎng)站、成都網(wǎng)站建設(shè)、鄞州網(wǎng)絡(luò)推廣、微信平臺小程序開發(fā)、鄞州網(wǎng)絡(luò)營銷、鄞州企業(yè)策劃、鄞州品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;成都創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供鄞州建站搭建服務(wù),24小時服務(wù)熱線:18982081108,官方網(wǎng)址:muchs.cn

分頁查詢
需求分析:在列表頁面中,顯示指定條數(shù)的數(shù)據(jù),通過翻頁按鈕完成首頁/上一頁/下一頁/尾頁的查詢
數(shù)據(jù)分析:
通過觀察,頁面上需要顯示下面的幾個數(shù)據(jù):
當(dāng)前頁:currentPage
頁面大小:pageSize
總頁數(shù):totalPage
首頁:1
上一頁:prevPage
下一頁:nextPage
尾頁:endPage
總條數(shù):totalCount
結(jié)果集:result
多條件過濾引發(fā)的那些小小疑慮

那么,我們應(yīng)該如何方便快速的將這多個數(shù)據(jù)共享到頁面上呢?答案是:封裝
我們應(yīng)該將這幾個參數(shù)封裝到一個對象中,然后共享這個對象即可,所以,我們有了下面這個類
@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;
}

}
在這個類中,我們提供了一個構(gòu)造器來快速封裝數(shù)據(jù)
其中,endPage/prevPage/nextPage是通過上面的幾個參數(shù)計算得來的
在這些數(shù)據(jù)中,存在兩個需要從數(shù)據(jù)庫中查詢得到的數(shù)據(jù):總條數(shù)/結(jié)果集
這兩個數(shù)據(jù)我們需要下面兩條SQL進(jìn)行查詢
查詢部門表中數(shù)據(jù)的總條數(shù)
SELECT count(id) FROM department
使用LIMIT關(guān)鍵字查詢指定頁面的數(shù)據(jù)
SELECT id, name, sn FROM department LIMIT #{start}, #{pageSize}
#{start}: 使用(currentPage-1)pageSize表達(dá)式計算出來的開始索引#{pageSize}: 每次查詢的最大條數(shù)
要執(zhí)行這兩條SQL,需要用戶傳遞兩個參數(shù):currentPage和pageSize
為了參數(shù)方便傳遞,我們將這兩個參數(shù)封裝到一個類中:QueryObject
@Setter@Getterpublic class QueryObject {
// 默認(rèn)查詢第一頁的數(shù)據(jù)
private int currentPage = 1;
// 頁面中默認(rèn)顯示10條數(shù)據(jù)
private int pageSize = 5;
public int getStart(){
return (currentPage - 1)
pageSize;
}
}
可以看出,查詢結(jié)果集中的#{start}表達(dá)式,是訪問查詢對象中的getStart()方法來獲取到計算得到的開始索引
到此,我們都已經(jīng)封裝好了分頁查詢中最核心的兩個類:
QueryObject:封裝用戶傳遞過來的currentPage/pageSize
PageResult:封裝頁面上顯示需要的result/totalCount/currentPage/pageSize/totalPage/prevPage/pageSize
有了這兩個類,我們就可以在service中定義下面的方法,來處理分頁查詢的業(yè)務(wù)了:

public PageResult query(QueryObject qo) {
    //查詢表中數(shù)據(jù)的總條數(shù)
    int totalCount = dao.queryForCount(qo);
    //當(dāng)查詢到的總條數(shù)為0時,說明沒有數(shù)據(jù),此時就不應(yīng)該再之后下面的查詢
    //直接返回相應(yīng)的默認(rèn)值即可
    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;
}

該方法接收用戶傳遞的數(shù)據(jù)(QueryObject),返回用戶需要的數(shù)據(jù)(PageResult)
通過調(diào)用dao中的兩個方法執(zhí)行兩條SQL查詢數(shù)據(jù)(總條數(shù)和結(jié)果集)
<!--查詢總條數(shù)--><select id="queryForCount" resultType="java.lang.Integer">
SELECT count(id)
FROM department
</select><!--查詢結(jié)果集-->
<select id="queryForList" resultType="Department">
SELECT
id,
name,
sn
FROM department
LIMIT #{start}, #{pageSize}
</select>
然后將數(shù)據(jù)封裝到PageResult對象中返回給表現(xiàn)層
表現(xiàn)層獲取到service中封裝的PageResult對象后,共享到request作用域中
然后請求轉(zhuǎn)發(fā)到list.jsp頁面
protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接收用戶傳遞的currentPage和pageSize
String currentPage = req.getParameter("currentPage");
String pageSize = req.getParameter("pageSize");
//將數(shù)據(jù)封裝到QueryObject中,傳遞給service進(jìn)行處理
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);
//請求轉(zhuǎn)發(fā)回到list.jsp頁面
req.getRequestDispatcher("/WEB-INF/views/department/list.jsp").forward(req, resp);
}
在list.jsp頁面上,使用EL+JSTL獲取數(shù)據(jù)并顯示在對應(yīng)的位置
部門列表
<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>

 當(dāng)前頁: ${result.currentPage} / ${result.endPage}

 跳轉(zhuǎn)到第: <input id="currentPage" name="currentPage" 
              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>

效果如下
多條件過濾引發(fā)的那些小小疑慮

說明:
在點擊翻頁的時候,通過執(zhí)行相應(yīng)的JS代碼提交表單來發(fā)起請求
將需要查詢的當(dāng)前頁的值設(shè)值給表單中的id為currentPage的輸入框,然后提交表單
目的主要是和后面的高級查詢進(jìn)行合并使用
做到這里,我們部門的分頁功能就完成了
因為部門的字段比較少,所以,在這個模塊中,沒有設(shè)計高級查詢的功能,這個功能我們在員工模塊中再去實現(xiàn)
接下來,我們來看看員工模塊相應(yīng)功能的實現(xiàn)

在完成部門的CRUD和分頁查詢后發(fā)現(xiàn),其他模塊的這些功能基本相似
不同之處主要在于字段不同而已,所以,在這里,我們主要對這些不同點進(jìn)行說明,其他的按照前面的實現(xiàn)即可
首先,來看看員工的表結(jié)構(gòu)

多條件過濾引發(fā)的那些小小疑慮

在該表中,前六個字段都是基本的字段,第七個(dept_id),這個字段是關(guān)聯(lián)部門的外鍵列
所以,待會兒我們在完成CRUD的過程中,需要注意維護(hù)該字段的值
清楚表結(jié)構(gòu)之后,我們來對員工的CRUD做一個簡單的分析
查詢功能:

多條件過濾引發(fā)的那些小小疑慮

可以看到,處理部門這一列顯示的數(shù)據(jù)比較特殊之外,其他的都是基本的數(shù)據(jù)展示而已
什么是特殊?什么是不特殊?
員工除了部門的信息外,其他的數(shù)據(jù)都是直接來自于數(shù)據(jù)庫,而部門在表中只存儲了對應(yīng)的編號,但是頁面上需要顯示部門的名稱,那么這個問題我們是怎么解決的呢?
好,首先解釋一下,這個問題的解決方案在目前我們的web階段還沒有涉及過,所以,我在這只能點到為止
我們的解決方案是:在執(zhí)行該數(shù)據(jù)的查詢的時候,使用多表查詢,將員工及其所在部門的信息查詢出來,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能夠查詢到如下的結(jié)果

多條件過濾引發(fā)的那些小小疑慮

然后在resultMap中如下的配置,完成數(shù)據(jù)的封裝,員工相關(guān)的數(shù)據(jù)封裝到Employee對象中,部門相關(guān)的數(shù)據(jù)封裝到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"/>
<!-- 一對多關(guān)系 -->
<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表達(dá)式,就能夠獲取到當(dāng)前員工所在部門的相關(guān)信息了
<td>${entity.dept.name}</td>
查詢功能分析到此結(jié)束,其他功能和部門的一致
新增功能:
需求分析:
保存用戶的相關(guān)信息,包括用戶所在部門的信息
通過對員工表的觀察發(fā)現(xiàn),表中關(guān)聯(lián)了部門的主鍵信息,來說明當(dāng)前員工所在的部門
所以,在保存員工的時候,需要為員工設(shè)置所在的部門.頁面設(shè)計如下

多條件過濾引發(fā)的那些小小疑慮

為員工設(shè)置所在的部門,用戶只需要進(jìn)行選擇即可,然后將選中部門的id傳遞到服務(wù)端
那么問題來了,如何將部門id通過下拉框傳遞到服務(wù)端呢?請看下面的分析
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>
首先,在跳轉(zhuǎn)到該頁面之間,我們先將所有的部門信息查詢到
然后在頁面上循環(huán)遍歷,生成對應(yīng)的option元素,將部門的id作為option的value(提交的數(shù)據(jù)),將部門的name作為option的文本內(nèi)容(顯示的數(shù)據(jù))
最后,在用戶選擇對應(yīng)選項后,提交表單,會將對應(yīng)option元素的value提交到后臺,完整數(shù)據(jù)如下:

多條件過濾引發(fā)的那些小小疑慮

通過上圖,可以清晰的看到,我們已經(jīng)將完整的數(shù)據(jù)提交到后臺
后臺獲取到這些數(shù)據(jù)之后,就能夠?qū)⑵浔4娴綌?shù)據(jù)庫中
那么,我們的保存功能就算完成了
更新功能:
更新和保存只有一個地方不同,就是需要數(shù)據(jù)回顯
而數(shù)據(jù)回顯中,我們只對部門(下拉框)和超級管理員(復(fù)選框)做一個說明,其他的因為都是普通的input元素,使用value屬性顯示數(shù)據(jù)即可
而下拉框和復(fù)選框需要單獨進(jìn)行處理,如下:
<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表達(dá)式的三元運算符進(jìn)行判斷,為下拉框添加selected屬性,為復(fù)選框添加checked屬性
編輯的時候,數(shù)據(jù)能回顯,接下來的操作和新增一致
刪除功能
和部門的刪除一致,這里就不再贅述
到此,員工的CRUD結(jié)束
高級查詢
功能需求:
輸入關(guān)鍵字和部門信息進(jìn)去過濾查詢,關(guān)鍵字是根據(jù)姓名和郵箱兩個字段查詢
頁面設(shè)計
多條件過濾引發(fā)的那些小小疑慮

高級查詢效果圖
當(dāng)用戶輸入關(guān)鍵字"趙"和部門"總經(jīng)辦"后,在列表中顯示的查詢結(jié)果則為所有總經(jīng)辦姓趙的員工
那么此時應(yīng)該執(zhí)行下面的SQL來查詢相應(yīng)的數(shù)據(jù)
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后面的條件是根據(jù)用戶傳遞的高級查詢相關(guān)的參數(shù)拼接而來
這里,我們需要解決兩個問題:
1.這里的多個高級查詢的參數(shù)如何傳遞?
對于這個問題,我們應(yīng)該能夠比較快的想到解決方案---數(shù)據(jù)封裝,如下:
@Setter@Getterpublic class EmployeeQueryObject extends QueryObject {
private String keyword; //按照員工名稱與郵箱模糊查詢
private Long deptId = -1L; //按照部門id查詢

//當(dāng)keyword為null或者空字符串的時候,都視為null處理
public String getKeyword(){
    return StringUtils.isEmpty(keyword) ? null : keyword;
}

}
2.參數(shù)拿到后,如何拼接到對應(yīng)的SQL中?
使用mybatis中的動態(tài)SQL中提供的標(biāo)簽,在mapper映射文件中進(jìn)行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>
以上兩個問題解決后,我們就可以根據(jù)用戶傳遞過來的參數(shù),執(zhí)行對應(yīng)的過濾查詢的SQL
最后,和分頁查詢的邏輯一樣,將數(shù)據(jù)封裝到PageResult中,和分頁相關(guān)的數(shù)據(jù)一同返回到頁面
效果如[高級查詢效果圖]所示
好了,基本功能是完成了,我們再來看看下面的問題:
首先,在表單中輸入下面的參數(shù),然后查詢
多條件過濾引發(fā)的那些小小疑慮

然后點擊下一頁進(jìn)行翻頁

多條件過濾引發(fā)的那些小小疑慮

可以看到,在點擊翻頁之后,我們不是在上面的基礎(chǔ)上查詢下一頁的數(shù)據(jù),而是查詢到了所有的數(shù)據(jù),WHY?
其實很簡單,來看看我們的請求參數(shù),一切就清楚了
在我們點擊翻頁的時候,傳遞的參數(shù)只有currentPage,并沒有將之前的高級查詢的參數(shù)一起傳遞到后臺,所以執(zhí)行了下面的SQL查詢到上面的結(jié)果
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 ?, ?
所以,要想在之前高級查詢的基礎(chǔ)上,繼續(xù)進(jìn)行分頁查詢,那么我們只有一個辦法,就是在翻頁的時候?qū)⒏呒壊樵兒头猪摰膮?shù)一起提交到后臺,拼接執(zhí)行相應(yīng)的SQL才行
解決方案:
使用JS來完成數(shù)據(jù)的提交(JS在目前階段還未進(jìn)行系統(tǒng)學(xué)習(xí),所以,這里大家重點應(yīng)該是放在我們要做的事情上,而不是怎么做)
<script type="text/javascript">
function goPage(currentPage) {
//為表單中的currentPage輸入框設(shè)值
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>
在點擊翻頁按鈕時,調(diào)用定義好的goPage函數(shù),完成其中的兩件事即可
此時,我們可以看到問題已然解決
最后,頁面跳轉(zhuǎn)和頁面大小的設(shè)置功能,我們不做要求,如果要實現(xiàn)也很簡單,我這里就直接把相關(guān)代碼貼出來
跳轉(zhuǎn)到第: <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>

好了,高級查詢的功能實現(xiàn)到此結(jié)束,我們來做一個小結(jié)
高級查詢和分頁的功能,我們應(yīng)該重點分析兩個點
1.用戶需要看到什么數(shù)據(jù)?
2.這些數(shù)據(jù)應(yīng)該執(zhí)行什么樣的SQL才能查詢到?
如果將這兩個問題分析清楚了,那么大家就能夠知道這個過程中所封裝的幾個類的作用了
QueryObject:封裝查詢對象中通用的屬性
EmployeeQueryObject:封裝高級查詢相關(guān)的條件參數(shù)
PageResult:封裝用戶需要使用到的數(shù)據(jù)
所以實現(xiàn)步驟大致如下:
1.獲取到用戶傳遞的高級查詢和分頁的參數(shù),封裝到對象的查詢對象中
2.從查詢對象中取出數(shù)據(jù),然后拼接SQL
3.將查詢之后得到的結(jié)果,封裝到PageResult對象中
4.頁面獲取到PageResult中的數(shù)據(jù)進(jìn)行顯示

Javaweb還有很多神奇的地方需要我們探索,Java學(xué)習(xí)之路是永遠(yuǎn)不會停止的,如果你想繼續(xù)提升自己,那就加入我們,在這里不僅會有大量的教程,還有很多java界大佬為你解答問題,幫助大家就是我們的目標(biāo)。

本文題目:多條件過濾引發(fā)的那些小小疑慮
本文網(wǎng)址:http://muchs.cn/article48/gddchp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、虛擬主機(jī)、商城網(wǎng)站動態(tài)網(wǎng)站、品牌網(wǎng)站制作網(wǎng)站設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名