Java单体应用 - 项目实战(后台) - 03.后台账户管理 - 06.搜索功能

原文地址:http://www.work100.net/training/monolithic-project-iot-cloud-admin-manager-search.html
更多教程:光束云 - 免费课程

搜索功能

序号 文内章节 视频
1 概述 -
2 使用动态SQL -
3 修改AuthManagerDao接口 -
4 修改AuthManagerService接口 -
5 定义搜索器ManagerSearcher -
6 修改AuthManagerServiceImpl实现 -
7 修改ManagerController -
8 修改视图文件 -
9 测试验证 -
10 实例源码 -

请参照如上章节导航进行阅读

1.概述

接下来实现 账户列表 页面的 搜索功能,预期实现的画面效果如下:

1.1.简单搜索

Java单体应用 - 项目实战(后台) - 03.后台账户管理 - 06.搜索功能

1.2.复杂搜索

Java单体应用 - 项目实战(后台) - 03.后台账户管理 - 06.搜索功能

2.使用动态SQL

因搜索功能的查询条件是动态变化的,所以我们的查询语句也需要动态生成,这里就需要使用我们前述章节 MyBatis 动态 SQL 讲述的知识。

我们在 AuthManagerMapper.xml 映射文件中新增一个 select 语句 search,代码如下:

<select id="search" resultType="AuthManager">
    SELECT
      <include refid="authManagerColumns" />
    FROM
      auth_manager AS a
    <where>
        <if test="userName != null and userName != ''">
            AND a.user_name LIKE CONCAT('%', #{userName}, '%')
        </if>
        <if test="roles != null and roles != ''">
            AND a.roles LIKE CONCAT('%', #{roles}, '%')
        </if>
        <if test="status != -1">
            AND a.status = #{status}
        </if>
    </where>
    ORDER BY a.id DESC
</select>

3.修改AuthManagerDao接口

增加 search 方法,代码如下:

/**
 * 搜索
 *
 * @param authManager
 * @return
 */
List<AuthManager> search(AuthManager authManager);

4.修改AuthManagerService接口

增加 search 方法,代码如下:

/**
 * 搜索
 *
 * @param managerSearcher 搜索器
 * @return
 */
List<AuthManager> search(ManagerSearcher managerSearcher);

这里面我们引入了 ManagerSearcher 搜索器类,该类用于传递查询参数,下面将完成其实现代码

5.定义搜索器ManagerSearcher

5.1.BaseSearcher 类

iot-cloud-commons 项目下的 net.work100.training.stage2.iot.cloud.commons.dto 包中新增一个 BaseSearcher 类,代码如下:

package net.work100.training.stage2.iot.cloud.commons.dto;

import java.io.Serializable;

/**
 * <p>Title: Searcher</p>
 * <p>Description: </p>
 *
 * @author liuxiaojun
 * @date 2020-03-08 16:45
 * ------------------- History -------------------
 * <date>      <author>       <desc>
 * 2020-03-08   liuxiaojun     初始创建
 * -----------------------------------------------
 */
public abstract class BaseSearcher implements Serializable {
    private String keyword;
    private boolean advanced;

    public String getKeyword() {
        return keyword;
    }

    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }

    public boolean isAdvanced() {
        return advanced;
    }

    public void setAdvanced(boolean advanced) {
        this.advanced = advanced;
    }
}

5.2.ManagerSearcher 类

iot-cloud-web-admin 项目下增加一个 net.work100.training.stage2.iot.cloud.web.admin.dto.auth 类包,然后该类包下新建一个 ManagerSearcher 类,代码如下:

package net.work100.training.stage2.iot.cloud.web.admin.dto.auth;

import net.work100.training.stage2.iot.cloud.commons.dto.BaseSearcher;

/**
 * <p>Title: ManagerSearcher</p>
 * <p>Description: </p>
 * <p>Url: http://www.work100.net/training/monolithic-project-iot-cloud-admin.html</p>
 *
 * @author liuxiaojun
 * @date 2020-03-08 17:02
 * ------------------- History -------------------
 * <date>      <author>       <desc>
 * 2020-03-08   liuxiaojun     初始创建
 * -----------------------------------------------
 */
public class ManagerSearcher extends BaseSearcher {

    private String userName;
    private String roles;
    private int status;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getRoles() {
        return roles;
    }

    public void setRoles(String roles) {
        this.roles = roles;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }
}

6.修改AuthManagerServiceImpl实现

实现 search 方法,代码如下:

@Override
public List<AuthManager> search(ManagerSearcher managerSearcher) {
    AuthManager authManager = new AuthManager();
    if (!managerSearcher.isAdvanced()) {
        authManager.setUserName(managerSearcher.getKeyword());
        authManager.setRoles("");
        authManager.setStatus(-1);
    } else {
        authManager.setUserName(managerSearcher.getUserName());
        authManager.setRoles(managerSearcher.getRoles());
        authManager.setStatus(managerSearcher.getStatus());
    }
    return authManagerDao.search(authManager);
}

7.修改ManagerController

7.1.修改 list 方法

@RequestMapping(value = "list", method = RequestMethod.GET)
public String list(Model model) {
    ManagerSearcher managerSearcher = new ManagerSearcher();
    managerSearcher.setKeyword("");
    managerSearcher.setAdvanced(false);
    managerSearcher.setRoles("");
    managerSearcher.setStatus(-1);
    model.addAttribute(managerSearcher);

    List<AuthManager> authManagers = authManagerService.selectAll();
    model.addAttribute("authManagers", authManagers);
    return "auth/manager_list";
}

7.2.新增 search 方法

@RequestMapping(value = "search", method = RequestMethod.POST)
public String search(ManagerSearcher managerSearcher, Model model) {

    List<AuthManager> authManagers = authManagerService.search(managerSearcher);
    model.addAttribute("managerSearcher", managerSearcher);
    model.addAttribute("authManagers", authManagers);
    return "auth/manager_list";
}

8.修改视图文件

下面修改视图文件 manager_list.jsp 的实现代码。

8.1.引入 form 表单标签库

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

8.2.搜索功能实现

修改 <div class="card"> 标签部分代码,修改后的代码如下:

<form:form action="/auth/manager/search" method="post" modelAttribute="managerSearcher">
    <form:hidden path="advanced" />
    <div class="card">
        <div class="card-header">
            <div class="card-title">
                <div class="btn-group">
                    <a href="/auth/manager/add" type="button" class="btn btn-primary">新增</a>
                    <button type="button" class="btn btn-default">更多...</button>
                    <button type="button" class="btn btn-default dropdown-toggle dropdown-icon" data-toggle="dropdown">
                        <span class="sr-only">Toggle Dropdown</span>
                        <div class="dropdown-menu" role="menu">
                            <a class="dropdown-item" href="#">批量锁定</a>
                            <a class="dropdown-item" href="#">批量解锁</a>
                            <div class="dropdown-divider"></div>
                            <a class="dropdown-item" href="#">批量删除</a>
                        </div>
                    </button>
                </div>
                <div class="btn-group">
                    <a href="/auth/manager/list" type="button" class="btn btn-default" title="重新加载"><i class="fas fa-redo"></i></a>
                    <button type="button" class="btn btn-default" title="打印"><i class="fas fa-print"></i></button>
                    <button type="button" class="btn btn-default" title="下载"><i class="fas fa-download"></i></button>
                </div>
            </div>
            <div id="btnOpen" class="card-tools" style="display: ${managerSearcher.advanced?"none":"block"};">
                <div class="input-group" style="padding-top: 5px;">
                    <form:input path="keyword" cssClass="form-control" placeholder="关键字:用户名" />
                    <div class="input-group-append">
                        <button type="submit" class="btn btn-default">搜索
                            <i class="fas fa-search"></i></button>
                    </div>
                    <div class="input-group-append">
                        <button type="button" class="btn btn-default" title="展开更多" onclick="showSearcher()">
                            展开 <i class="fas fa-angle-double-down"></i></button>
                    </div>
                </div>
            </div>
            <div id="btnClose" class="card-tools" style="display: ${managerSearcher.advanced?"block":"none"};">
                <div class="input-group" style="padding-top: 5px;">
                    <div class="input-group-append">
                        <button type="button" class="btn btn-default" title="合拢更多" onclick="hideSearcher()">
                            合拢 <i class="fas fa-angle-double-up"></i></button>
                    </div>
                </div>
            </div>
        </div>
        <div class="card-header" id="searcher" style="display: ${managerSearcher.advanced?"block":"none"};background-color: #f2f4f8;">
            <div class="row">
                <div class="col-md-9">
                    <div class="input-group">
                        <form:input path="userName" cssClass="form-control" placeholder="用户名" />
                        <form:select path="roles" class="form-control select2" style="width: 150px;">
                            <option value="" ${managerSearcher.roles == "" ? "selected" : ""}>
                                角色
                            </option>
                            <option value="admin" ${managerSearcher.roles == "admin" ? "selected" : ""}>
                                admin
                            </option>
                            <option value="editor" ${managerSearcher.roles == "editor" ? "selected" : ""}>
                                editor
                            </option>
                        </form:select>
                        <form:select path="status" class="form-control select2" style="width: 150px;">
                            <option value="-1" ${managerSearcher.status == -1 ? "selected" : ""}>
                                状态
                            </option>
                            <option value="0" ${managerSearcher.status == 0 ? "selected" : ""}>
                                未激活
                            </option>
                            <option value="1" ${managerSearcher.status == 1 ? "selected" : ""}>
                                激活
                            </option>
                            <option value="2" ${managerSearcher.status == 2 ? "selected" : ""}>
                                锁定
                            </option>
                            <option value="3" ${managerSearcher.status == 3 ? "selected" : ""}>
                                删除
                            </option>
                        </form:select>
                    </div>
                </div>
                <div class="col-md-3">
                    <div class="btn-group">
                        <button type="submit" class="btn btn-primary">搜 索</button>
                    </div>
                    <div class="btn-group">
                        <a href="/auth/manager/list" type="button" class="btn btn-default">重 置</a>
                    </div>
                </div>
            </div>
        </div>
        <div class="card-body table-responsive p-0">
            <table class="table table-hover text-nowrap">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>用户名</th>
                    <th>角色</th>
                    <th>超级用户</th>
                    <th>状态</th>
                    <th>更新时间</th>
                    <th width="120px" align="center">操作</th>
                </tr>
                </thead>
                <tbody>
                <c:forEach items="${authManagers}" var="authManager">
                    <tr>
                        <td>${authManager.id}</td>
                        <td>${authManager.userName}</td>
                        <td>${authManager.roles}</td>
                        <td>${authManager.superuser?"是":"否"}</td>
                        <td>
                            <c:choose>
                                <c:when test="${authManager.status==0}">
                                    <label class="text-muted">未激活</label>
                                </c:when>
                                <c:when test="${authManager.status==1}">
                                    <label class="text-success">已激活</label>
                                </c:when>
                                <c:when test="${authManager.status==2}">
                                    <label class="text-warning">锁定</label>
                                </c:when>
                                <c:when test="${authManager.status==3}">
                                    <label class="text-danger">被删除</label>
                                </c:when>
                            </c:choose>
                        </td>
                        <td>
                            <fmt:formatDate value="${authManager.updated}" pattern="yyyy-MM-dd HH:mm:ss" /></td>
                        <td>
                            <div class="btn-group">
                                <a href="#" type="button" class="btn btn-default btn-sm"><i class="fas fa-eye"></i></a>
                                <a href="/auth/manager/edit/${authManager.userKey}" type="button" class="btn btn-primary btn-sm"><i class="fas fa-edit"></i></a>
                                <button type="button" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#modal-operate-confirm" data-whatever="${authManager.userKey}">
                                    <i class="fas fa-trash"></i></button>
                            </div>
                        </td>
                    </tr>
                </c:forEach>
                </tbody>
            </table>
        </div>
        <!-- /.card-body -->
    </div>
    <!-- /.card -->
</form:form>

8.3.修改 JS 脚本

修改页面中自定义的 JS 脚本,增加 select 控件的初始化,以及增加 高级搜索 表单的显示隐藏功能,代码如下:

$(function() {
    //Initialize Select2 Elements
    $('.select2').select2();

    //Initialize Select2 Elements
    $('.select2bs4').select2({
        theme: 'bootstrap4'
    });

    if (${baseResult.status != null && baseResult.status == 200}) {
        const Toast = Swal.mixin({
            toast: true,
            position: 'top',
            showConfirmButton: false,
            timer: 2000,
            timerProgressBar: true
        })

        Toast.fire({
            type: 'success',
            title: '${baseResult.message}'
        })
    }

    $('#modal-operate-confirm').on('show.bs.modal', function(event) {
        let trigger = $(event.relatedTarget)
        let userKey = trigger.data('whatever')
        let modal = $(this)
        let ok = modal.find('.modal-footer button')[1]
        $(ok).click(function(e) {
            location.href = '/auth/manager/delete/' + userKey
        })
    })
})

// 显示高级搜索
function showSearcher() {
    $("#advanced").val(true);
    $("#searcher").css('display', 'block');
    $("#btnOpen").css('display', 'none');
    $("#btnClose").css('display', 'block');
}

// 隐藏高级搜索
function hideSearcher() {
    $("#advanced").val(false);
    $("#searcher").css('display', 'none');
    $("#btnOpen").css('display', 'block');
    $("#btnClose").css('display', 'none');
}

8.4.完整代码

视图 manager_list.jsp 文件的完整代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
    <title>查询列表 - 后台账户 | IoT-Admin</title>
    <jsp:include page="../includes/resources_head.jsp" />
</head>
<body class="hold-transition sidebar-mini">
<div class="wrapper">

    <jsp:include page="../includes/layout_header.jsp" />

    <jsp:include page="../includes/layout_left.jsp" />

    <!-- Content Wrapper. Contains page content -->
    <div class="content-wrapper">
        <!-- Content Header (Page header) -->
        <div class="content-header">
            <div class="container-fluid">
                <div class="row mb-2">
                    <div class="col-sm-6">
                        <h1 class="m-0 text-dark">查询列表</h1>
                    </div><!-- /.col -->
                    <div class="col-sm-6">
                        <ol class="breadcrumb float-sm-right">
                            <li class="breadcrumb-item"><a href="#">后台账户</a></li>
                            <li class="breadcrumb-item active">查询列表</li>
                        </ol>
                    </div><!-- /.col -->
                </div><!-- /.row -->
            </div><!-- /.container-fluid -->
        </div>
        <!-- /.content-header -->

        <!-- Main content -->
        <div class="content">
            <div class="container-fluid">
                <div class="row">
                    <div class="col">
                        <form:form action="/auth/manager/search" method="post" modelAttribute="managerSearcher">
                            <form:hidden path="advanced" />
                            <div class="card">
                                <div class="card-header">
                                    <div class="card-title">
                                        <div class="btn-group">
                                            <a href="/auth/manager/add" type="button" class="btn btn-primary">新增</a>
                                            <button type="button" class="btn btn-default">更多...</button>
                                            <button type="button" class="btn btn-default dropdown-toggle dropdown-icon" data-toggle="dropdown">
                                                <span class="sr-only">Toggle Dropdown</span>
                                                <div class="dropdown-menu" role="menu">
                                                    <a class="dropdown-item" href="#">批量锁定</a>
                                                    <a class="dropdown-item" href="#">批量解锁</a>
                                                    <div class="dropdown-divider"></div>
                                                    <a class="dropdown-item" href="#">批量删除</a>
                                                </div>
                                            </button>
                                        </div>
                                        <div class="btn-group">
                                            <a href="/auth/manager/list" type="button" class="btn btn-default" title="重新加载"><i class="fas fa-redo"></i></a>
                                            <button type="button" class="btn btn-default" title="打印"><i class="fas fa-print"></i></button>
                                            <button type="button" class="btn btn-default" title="下载"><i class="fas fa-download"></i></button>
                                        </div>
                                    </div>
                                    <div id="btnOpen" class="card-tools" style="display: ${managerSearcher.advanced?"none":"block"};">
                                        <div class="input-group" style="padding-top: 5px;">
                                            <form:input path="keyword" cssClass="form-control" placeholder="关键字:用户名" />
                                            <div class="input-group-append">
                                                <button type="submit" class="btn btn-default">搜索
                                                    <i class="fas fa-search"></i></button>
                                            </div>
                                            <div class="input-group-append">
                                                <button type="button" class="btn btn-default" title="展开更多" onclick="showSearcher()">
                                                    展开 <i class="fas fa-angle-double-down"></i></button>
                                            </div>
                                        </div>
                                    </div>
                                    <div id="btnClose" class="card-tools" style="display: ${managerSearcher.advanced?"block":"none"};">
                                        <div class="input-group" style="padding-top: 5px;">
                                            <div class="input-group-append">
                                                <button type="button" class="btn btn-default" title="合拢更多" onclick="hideSearcher()">
                                                    合拢 <i class="fas fa-angle-double-up"></i></button>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="card-header" id="searcher" style="display: ${managerSearcher.advanced?"block":"none"};background-color: #f2f4f8;">
                                    <div class="row">
                                        <div class="col-md-9">
                                            <div class="input-group">
                                                <form:input path="userName" cssClass="form-control" placeholder="用户名" />
                                                <form:select path="roles" class="form-control select2" style="width: 150px;">
                                                    <option value="" ${managerSearcher.roles == "" ? "selected" : ""}>
                                                        角色
                                                    </option>
                                                    <option value="admin" ${managerSearcher.roles == "admin" ? "selected" : ""}>
                                                        admin
                                                    </option>
                                                    <option value="editor" ${managerSearcher.roles == "editor" ? "selected" : ""}>
                                                        editor
                                                    </option>
                                                </form:select>
                                                <form:select path="status" class="form-control select2" style="width: 150px;">
                                                    <option value="-1" ${managerSearcher.status == -1 ? "selected" : ""}>
                                                        状态
                                                    </option>
                                                    <option value="0" ${managerSearcher.status == 0 ? "selected" : ""}>
                                                        未激活
                                                    </option>
                                                    <option value="1" ${managerSearcher.status == 1 ? "selected" : ""}>
                                                        激活
                                                    </option>
                                                    <option value="2" ${managerSearcher.status == 2 ? "selected" : ""}>
                                                        锁定
                                                    </option>
                                                    <option value="3" ${managerSearcher.status == 3 ? "selected" : ""}>
                                                        删除
                                                    </option>
                                                </form:select>
                                            </div>
                                        </div>
                                        <div class="col-md-3">
                                            <div class="btn-group">
                                                <button type="submit" class="btn btn-primary">搜 索</button>
                                            </div>
                                            <div class="btn-group">
                                                <a href="/auth/manager/list" type="button" class="btn btn-default">重 置</a>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="card-body table-responsive p-0">
                                    <table class="table table-hover text-nowrap">
                                        <thead>
                                        <tr>
                                            <th>ID</th>
                                            <th>用户名</th>
                                            <th>角色</th>
                                            <th>超级用户</th>
                                            <th>状态</th>
                                            <th>更新时间</th>
                                            <th width="120px" align="center">操作</th>
                                        </tr>
                                        </thead>
                                        <tbody>
                                        <c:forEach items="${authManagers}" var="authManager">
                                            <tr>
                                                <td>${authManager.id}</td>
                                                <td>${authManager.userName}</td>
                                                <td>${authManager.roles}</td>
                                                <td>${authManager.superuser?"是":"否"}</td>
                                                <td>
                                                    <c:choose>
                                                        <c:when test="${authManager.status==0}">
                                                            <label class="text-muted">未激活</label>
                                                        </c:when>
                                                        <c:when test="${authManager.status==1}">
                                                            <label class="text-success">已激活</label>
                                                        </c:when>
                                                        <c:when test="${authManager.status==2}">
                                                            <label class="text-warning">锁定</label>
                                                        </c:when>
                                                        <c:when test="${authManager.status==3}">
                                                            <label class="text-danger">被删除</label>
                                                        </c:when>
                                                    </c:choose>
                                                </td>
                                                <td>
                                                    <fmt:formatDate value="${authManager.updated}" pattern="yyyy-MM-dd HH:mm:ss" /></td>
                                                <td>
                                                    <div class="btn-group">
                                                        <a href="#" type="button" class="btn btn-default btn-sm"><i class="fas fa-eye"></i></a>
                                                        <a href="/auth/manager/edit/${authManager.userKey}" type="button" class="btn btn-primary btn-sm"><i class="fas fa-edit"></i></a>
                                                        <button type="button" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#modal-operate-confirm" data-whatever="${authManager.userKey}">
                                                            <i class="fas fa-trash"></i></button>
                                                    </div>
                                                </td>
                                            </tr>
                                        </c:forEach>
                                        </tbody>
                                    </table>
                                </div>
                                <!-- /.card-body -->
                            </div>
                            <!-- /.card -->
                        </form:form>
                    </div>
                </div>
            </div>
            <!-- /.container-fluid -->
        </div>
        <!-- /.content -->

        <div class="modal fade" id="modal-operate-confirm">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title">操作确认</h4>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body">
                        <p>操作后不可恢复,确定吗?</p>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
                        <button type="button" class="btn btn-primary">确定</button>
                    </div>
                </div>
                <!-- /.modal-content -->
            </div>
            <!-- /.modal-dialog -->
        </div>
        <!-- /.modal -->
    </div>
    <!-- /.content-wrapper -->

    <jsp:include page="../includes/layout_footer.jsp" />
</div>
<!-- ./wrapper -->
<jsp:include page="../includes/resources_body.jsp" />

<script>
$(function() {
    //Initialize Select2 Elements
    $('.select2').select2();

    //Initialize Select2 Elements
    $('.select2bs4').select2({
        theme: 'bootstrap4'
    });

    if (${baseResult.status != null && baseResult.status == 200}) {
        const Toast = Swal.mixin({
            toast: true,
            position: 'top',
            showConfirmButton: false,
            timer: 2000,
            timerProgressBar: true
        })

        Toast.fire({
            type: 'success',
            title: '${baseResult.message}'
        })
    }

    $('#modal-operate-confirm').on('show.bs.modal', function(event) {
        let trigger = $(event.relatedTarget)
        let userKey = trigger.data('whatever')
        let modal = $(this)
        let ok = modal.find('.modal-footer button')[1]
        $(ok).click(function(e) {
            location.href = '/auth/manager/delete/' + userKey
        })
    })
})

// 显示高级搜索
function showSearcher() {
    $("#advanced").val(true);
    $("#searcher").css('display', 'block');
    $("#btnOpen").css('display', 'none');
    $("#btnClose").css('display', 'block');
}

// 隐藏高级搜索
function hideSearcher() {
    $("#advanced").val(false);
    $("#searcher").css('display', 'none');
    $("#btnOpen").css('display', 'block');
    $("#btnClose").css('display', 'none');
}
</script>
</body>
</html>

9.测试验证

重启 Tomcat 运行并验证搜索功能效果。

10.实例源码

实例源码已经托管到如下地址:


上一篇:删除账户

上一篇:JS代码重构


如果对课程内容感兴趣,可以扫码关注我们的 公众号QQ群,及时关注我们的课程更新

Java单体应用 - 项目实战(后台) - 03.后台账户管理 - 06.搜索功能
Java单体应用 - 项目实战(后台) - 03.后台账户管理 - 06.搜索功能

上一篇:强大:MyBatis ,三种流式查询方法


下一篇:Hadoop完全分布式安装Hive