【尚筹网项目】 三、【后台】 管理员信息维护


一、分页显示管理员信息部分

(1) 思路

在这里插入图片描述

(2) 技术点

① 让 SQL 语句针对 keyword 时有时无的情况进行适配

使用 SQL 中做字符串连接的函数:CONCAT("%",#{keyword},"%")

  • keyword 有值:“like %tom%”
  • keyword 无值:“like %%”
② PageHelper 使用
  • 引入依赖

在这里插入图片描述

<!-- MyBatis分页插件 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
</dependency>
  • 在 SqlSessionFactoryBean 中配置 PageHelper

在这里插入图片描述

<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 装配数据源-->
    <property name="dataSource" ref="dataSource"/>
    <!-- 指定MyBatis 全局配置文件位置-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <!-- 指定Mapper 配置文件位置-->
    <property name="mapperLocations" value="classpath:mybatis/mapper/*Mapper.xml"/>
    <!-- 配置 MyBatis 的插件 -->
    <property name="plugins">
        <array>
            <!-- 配置 PageHelper -->
            <bean class="com.github.pagehelper.PageHelper">
                <!-- 配置相关属性 -->
                <property name="properties">
                    <props>
                        <!-- 配置数据库方言,告诉 PageHelper 当前使用的具体数据库,-->
                        <!-- 让 PageHelper 可以根据当前数据库生成对应的分页 SQL 语句 -->
                        <prop key="dialect">mysql</prop>
                        <!-- 配置页码的合理化修正 -->
                        <!-- 让 PageHelper 自动把浏览器传来的 PageNum 修正到 0~总页数范围 -->
                        <prop key="reasonable">true</prop>
                    </props>
                </property>
            </bean>
        </array>
    </property>
</bean>
  • 在 Java 代码中使用
PageHelper.startPage(pageNum, pageSize)

PageInfo<Admin> pageInfo = new PageInfo(adminList );
③ 显示页码

使用 jQuery 插件Pagination


(3) 后端代码

① 查询 Admin 数据的 SQL 语句

在这里插入图片描述

<select id="selectAdminListByKeyword" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List"/>
    from t_admin
    where login_acct like CONCAT("%",#{keyword},"%")
    or
    user_name like CONCAT("%",#{keyword},"%")
    or
    email like CONCAT("%",#{keyword},"%")
</select>
② AdminMapper 中的抽象方法

在这里插入图片描述

List<Admin> selectAdminListByKeyword(String keyword);
③ AdminService 方法

在这里插入图片描述

// 管理员分页
@Override
public PageInfo<Admin> getAdminPage(String keyword, Integer pageNum, Integer pageSize) {
    // 1.开启分页功能
    PageHelper.startPage(pageNum,pageSize);

    // 2.查询 Admin 数据
    List<Admin> admins = adminMapper.selectAdminListByKeyword(keyword);

    // 3.为了方便页面使用将 adminList 封装为 PageInfo
    PageInfo<Admin> pageInfo = new PageInfo<>(admins);

    return pageInfo;
}
④ AdminHandler 方法

在这里插入图片描述

// 管理员分页
@RequestMapping("/admin/page.html")
public String getAdminPage(
            // 注意:页面上有可能不提供关键词,要进行适配
            // 在@RequestParam注解中设置defaultValue属性为空字符串
            // 表示浏览器不提供关键词时keyword 变量赋值为空字符串
            @RequestParam(value="keyword", defaultValue="") String keyword,
            // 浏览器未提供 pageNum 时,默认前往第一页
            @RequestParam(value="pageNum", defaultValue="1") Integer pageNum,
            // 浏览器未提供 pageSize 时,默认每页显示 5 条记录
            @RequestParam(value="pageSize", defaultValue="5") Integer pageSize,
            ModelMap modelMap
        ) {

    // 查询得到分页结果
    PageInfo<Admin> pageInfo = adminService.getAdminPage(keyword, pageNum, pageSize);

    // 将分页数据存入模型
    modelMap.addAttribute(CrowdConstant.ATTR_NAME_PAGE_INFO,pageInfo);
    return "admin-page";
}

(4) 前端代码

① 准备 admin-page.jsp

在这里插入图片描述

② 在 admin-page 页面显示真实数据

在这里插入图片描述

<tbody>
<c:if test="${empty requestScope.pageInfo.list }">
   <tr>
       <td colspan="2">抱歉!没有查询到相关的数据!</td>
   </tr>
</c:if>
<c:if test="${!empty requestScope.pageInfo.list }">
   <c:forEach items="${requestScope.pageInfo.list }" var="admin" varStatus="myStatus">
       <tr>
           <td>${myStatus.count }</td>
           <td><input type="checkbox"></td>
           <td>${admin.loginAcct }</td>
           <td>${admin.userName }</td>
           <td>${admin.email }</td>
           <td>
               <button type="button" class="btn btn-success btn-xs">
                   <i class=" glyphicon glyphicon-check"></i>
               </button>
               <button type="button" class="btn btn-primary btn-xs">
                   <i class=" glyphicon glyphicon-pencil"></i>
               </button>
               <button type="button" class="btn btn-danger btn-xs">
                   <i class=" glyphicon glyphicon-remove"></i>
               </button>
           </td>
       </tr>
   </c:forEach>
</c:if>
</tbody>

在这里插入图片描述


二、分页导航条

(1) 加入 Pagination 插件环境

在这里插入图片描述

(2) 在页面上引入样式文件和 JavaScript 文件

在这里插入图片描述

<link rel="stylesheet" href="css/pagination.css">
<script type="text/javascript" src="jquery/jquery.pagination.js"></script>
★ 出现的问题
在href和src后的路径最前面加了../ ,一开始没加时,发现没有代码提示,
于是当时突然觉得是因为要先找到上一级目录,也就是webapp
再从该目录下寻找。

于是,pagination不生效了,找了半天错误,最后想起来在公共jsp中写了base
所以链接的前面不用写/了,大概率是因为这个原因,于是去掉../,问题得到解决

(3) 编写 Pagination 代码

<script type="text/javascript">
    $(function () {
        // 调用专门的函数初始化分页导航条
        initPagination();
    });

    // 声明一个函数用于初始化 Pagination
    function initPagination() {
        // 获取分页数据中的总记录数
        var totalRecord = ${requestScope.pageInfo.total};
        // 声明 Pagination 设置属性的 JSON 对象
        var properties = {
            num_edge_entries: 3,                                // 边缘页数
            num_display_entries: 5,                             // 主体页数
            callback: pageSelectCallback,                       // 用户点击“翻页”按钮之后执行翻页操作的回调函数
            current_page: ${requestScope.pageInfo.pageNum-1},   // 当前页,pageNum 从 1 开始,必须-1 后才可以赋值
            prev_text: "上一页",
            next_text: "下一页",
            items_per_page:${requestScope.pageInfo.pageSize}    // 每页显示 1 项
        };
        // 调用分页导航条对应的 jQuery 对象的 pagination()方法生成导航条
        $("#Pagination").pagination(totalRecord, properties);
    }

    // 翻页过程中执行的回调函数
    // 点击“上一页”、“下一页”或“数字页码”都会触发翻页动作,从而导致当前函数被调用
    // pageIndex 是用户在页面上点击的页码数值
    function pageSelectCallback(pageIndex, jQuery) {
        // pageIndex 是当前页页码的索引,相对于 pageNum 来说,pageIndex 比 pageNum 小 1
        var pageNum = pageIndex + 1;
        // 执行页面跳转也就是实现“翻页”
        window.location.href = "admin/page.html?pageNum=" + pageNum;
        // 取消当前超链接的默认行为
        return false;
    }
</script>

(4) 修改 jquery.pagination.js 文件源码

在这里插入图片描述
问题的解决:不让 Pagination 在页码导航条初始化完成时就调用回调函数!

在这里插入图片描述

(5) 添加数据库测试数据

@Test
public void test1() {
     for (int i = 2; i < 234; i++) {
         Admin admin = new Admin(null,"admin"+i,"admin"+i,"admin"+i,"admin"+i+"@qq.com",null);
         adminMapper.insertSelective(admin);
     }
 }

在这里插入图片描述


三、关键词查询

(1) 页面调整待提交的表单

在这里插入图片描述

<form action="admin/get/page.html" method="post" class="form-inline" role="form" style="float:left;">
    <div class="form-group has-feedback">
        <div class="input-group">
            <div class="input-group-addon">查询条件</div>
            <input name="keyword" class="form-control has-success" type="text" placeholder="请输入查询条件">
        </div>
    </div>
    <button type="submit" class="btn btn-warning"><i class="glyphicon glyphicon-search"></i> 查询
    </button>
</form>

(2) 在翻页时保持 keyword 值

// 执行页面跳转也就是实现“翻页“
window.location.href = "admin/get/page.html?pageNum="+pageNum+"&keyword=${param.keyword}";

四、单条删除 管理员

(1) 调整删除的按钮

在这里插入图片描述

<a href="admin/remove/${admin.id }/${requestScope.pageInfo.pageNum }/${param.keyword }.html" class="btn btn-danger btn-xs">
	<i class=" glyphicon glyphicon-remove"></i>
</a>

(2) AdminHandler

在这里插入图片描述

// 管理员单条删除
@RequestMapping("/admin/remove/{adminId}/{pageNum}/{keyword}.html")
public String removeAdmin(
        @PathVariable("adminId") int adminId,
        @PathVariable("pageNum") int pageNum,
        @PathVariable("keyword") String keyword
) {
    // 执行删除
    adminService.removeAdmin(adminId);

    // 页面跳转:回到分页页面

    // 尝试方案1:直接转发到admin-page.jsp会无法显示分页的数据
    // return "admin-page";

    // 尝试方案2:转发到/admin/get/page.html地址,一旦刷新页面会重新执行删除操作,浪费性能
    // return "forward:/admin/get/page.html";

    // 尝试方案3:重定向到/admin/get/page.html地址
    // 同时为了保持原本所在的页面和查询关键词再附加pageNum和keyword两个请求参数
     return "redirect:/admin/get/page.html?pageNum="+pageNum+"&keyword="+keyword;
}

(3) AdminService

void removeAdmin(int adminId);

(4) AdminServiceImpl

// 管理员删除
@Override
public void removeAdmin(int adminId) {
    adminMapper.deleteByPrimaryKey( adminId);
}

五、新增管理员信息

(1) 思路

在这里插入图片描述

(2) 代码

① 设置唯一约束
ALTER TABLE `t_admin` ADD UNIQUE INDEX (`login_acct`)
② AdminService

在这里插入图片描述

void addAdmin(Admin admin);
③ AdminServiceImpl

在这里插入图片描述

// 增加管理员
@Override
public void addAdmin(Admin admin) {
    // 生成当前系统时间
    Date date = new Date();
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String createTime = format.format(date);

    admin.setCreateTime(createTime);


    // 针对登录密码进行加密
    String userPswd = admin.getUserPswd();
    String encoded = CrowdUtil.md5(userPswd);

    admin.setUserPswd(encoded);

    // 执行保存,如果账户被占用会抛出异常
    try {
        adminMapper.insert(admin);

    }catch (Exception e) {
        e.printStackTrace();

        // 检测当前捕获的异常对象,如果是 DuplicateKeyException 类型说明是账号重复导致的
        if (e instanceof DuplicateKeyException) {
            // 抛出自定义的 LoginAcctAlreadyInUseException 异常
            throw new LoginAcctAlreadyInUseException(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
        }

        // 为了不掩盖问题,如果当前捕获到的不是 DuplicateKeyException 类型的异常,则把当前捕获到的异常对象继续向上抛出
        throw e;
    }
}
④ 异常映射处理器类

在这里插入图片描述

// 账号已存在异常
@ExceptionHandler(LoginAcctAlreadyInUseException.class)
public ModelAndView LoginAcctAlreadyInUseException(
        LoginAcctAlreadyInUseException exception,
        HttpServletRequest request,
        HttpServletResponse response
) throws IOException {
    // 只是指定当前异常对应的页面即可
    String viewName = "admin-add";
    
    return commonResolveException(exception, request, response, viewName);
}
⑤ 自定义异常

在这里插入图片描述

public class LoginAcctAlreadyInUseException extends RuntimeException{
    public LoginAcctAlreadyInUseException() {
        super();
    }

    public LoginAcctAlreadyInUseException(String message) {
        super(message);
    }

    public LoginAcctAlreadyInUseException(String message, Throwable cause) {
        super(message, cause);
    }

    public LoginAcctAlreadyInUseException(Throwable cause) {
        super(cause);
    }

    protected LoginAcctAlreadyInUseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
⑥ AdminHandler

在这里插入图片描述

// 添加管理员
@RequestMapping("/add/admin.html")
public String addAdmin(Admin admin) {
    // 执行添加
    adminService.addAdmin(admin);

    // 重定向到分页页面,使用重定向是为了避免刷新浏览器重复提交表单
    // 为了能看到刚添加的管理员,所以去到最后一页,
    return "redirect:/admin/get/page.html?pageNum="+Integer.MAX_VALUE;
}
⑦ 调整新增按钮

在这里插入图片描述

</button>
<%--旧代码--%>
<%--<button type="button" class="btn btn-primary" style="float:right;"--%>
<%--οnclick="window.location.href='add.html'"><i class="glyphicon glyphicon-plus"></i> 新增--%>
<%--</button>--%>

<%--新代码--%>
<a href="admin/to/add/page.html" class="btn btn-primary"><i class="glyphicon glyphicon-plus"></i></a>
⑧ 配置view-controller

在这里插入图片描述

<!-- 新增管理员页面-->
<mvc:view-controller path="/admin/to/add/page.html" view-name="admin-add" />
⑨ 准备表单页面 admin-add.jsp

在这里插入图片描述

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<%@include file="include-head.jsp" %>
<body>
<%@include file="include-nav.jsp" %>
<div class="container-fluid">
    <div class="row">
        <%@include file="include-sidebar.jsp" %>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <ol class="breadcrumb">
                <li><a href="admin/to/main/page.html">首页</a></li>
                <li><a href="admin/get/page.html">数据列表</a></li>
                <li class="active">新增</li>
            </ol>
            <div class="panel panel-default">
                <div class="panel-heading">表单数据<div style="float:right;cursor:pointer;" data-toggle="modal" data-target="#myModal"><i class="glyphicon glyphicon-question-sign"></i></div></div>
                <div class="panel-body">
                    <form action="add/admin.html" method="post" role="form">
                        <p>${requestScope.exception.message}</p>
                        <div class="form-group">
                            <label for="exampleInputPassword1">登录账号</label>
                            <input name="loginAcct"  type="text" class="form-control" id="exampleInputPassword1" placeholder="请输入登录账号">
                        </div>
                        <div class="form-group">
                            <label for="exampleInputPassword1">登录密码</label>
                            <input name="userPswd"  type="text" class="form-control" id="exampleInputPassword2" placeholder="请输入登录密码">
                        </div>
                        <div class="form-group">
                            <label for="exampleInputPassword1">用户昵称</label>
                            <input name="userName" type="text" class="form-control" id="exampleInputPassword3" placeholder="请输入用户昵称">
                        </div>
                        <div class="form-group">
                            <label for="exampleInputEmail1">邮箱地址</label>
                            <input name="email" type="email" class="form-control" id="exampleInputEmail1" placeholder="请输入邮箱地址">
                            <p class="help-block label label-warning">请输入合法的邮箱地址, 格式为: xxxx@xxxx.com</p>
                        </div>
                        <button type="submit" class="btn btn-success"><i class="glyphicon glyphicon-plus"></i> 新增</button>
                        <button type="reset" class="btn btn-danger"><i class="glyphicon glyphicon-refresh"></i> 重置</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

六、更新管理员信息

(1) 思路

在这里插入图片描述

(2) 代码

① 准备“更新”超链接

在这里插入图片描述

<%--旧代码--%>
<%--<button type="button" class="btn btn-success btn-xs">--%>
<%--<i class=" glyphicon glyphicon-check"></i>--%>
<%--</button>--%>
<%--新代码--%>
<a href="admin/to/edit/page.html?adminId=${admin.id}&pageNum=${requestScope.pageInfo.pageNum}&keyword=${param.keyword}" class="btn btn-success btn-xs">
       <i class=" glyphicon glyphicon-check"></i>
</a>
② handler 代码

在这里插入图片描述

// 更新管理员信息
@RequestMapping("/admin/to/edit/page.html")
public String editAdmin(@RequestParam("adminId") int adminId,ModelMap modelMap) {
    // 通过id获取修改的管理员
    Admin admin = adminService.getAdminById(adminId);

    // 将获取到的admin放入request域中
    modelMap.addAttribute("admin",admin);
    
    return "admin-edit";
}
③ AdminService

在这里插入图片描述

Admin getAdminById(int adminId);
④ AdminServiceImpl

在这里插入图片描述

// 通过id获取admin对象
@Override
public Admin getAdminById(int adminId) {
    return adminMapper.selectByPrimaryKey(adminId);
}
⑤ 调整修改的按钮

在这里插入图片描述

<%--旧代码--%>
<%--<button type="button" class="btn btn-success btn-xs">--%>
<%--<i class=" glyphicon glyphicon-check"></i>--%>
<%--</button>--%>
<%--新代码--%>
<a href="admin/to/edit/page.html?adminId=${admin.id}&pageNum=${requestScope.pageInfo.pageNum}&keyword=${param.keyword}" class="btn btn-success btn-xs">
    <i class=" glyphicon glyphicon-check"></i>
</a>
⑥ 准备表单页面 admin-edit.jsp

在这里插入图片描述


⑦ 执行更新
AdminHandler
// 更新管理员信息
@RequestMapping("/admin/update.html")
public String adminUpdate(Admin admin,
                          @RequestParam("pageNum") int pageNum,
                          @RequestParam("keyword") String keyword
                          ) {

    // 执行更新
    adminService.updateAdmin(admin);

    //
    return "redirect:/admin/get/page.html?pageNum="+pageNum+"&keyword="+keyword;
}
AdminService
void updateAdmin(Admin admin);
AdminServiceImpl
// 修改管理员信息
@Override
public void updateAdmin(Admin admin) {
    try {
        // "Selective" 表示有选择的更新,对于null值的字段不更新
        adminMapper.updateByPrimaryKeySelective(admin);

    }catch (Exception e) {
        e.printStackTrace();

        // 检测当前捕获的异常对象,如果是 DuplicateKeyException 类型说明是账号重复导致的
        if (e instanceof DuplicateKeyException) {
            // 抛出自定义的 LoginAcctAlreadyInUseException 异常
            throw new LoginAcctAlreadyInUseForUpdateException(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
        }

        // 为了不掩盖问题,如果当前捕获到的不是 DuplicateKeyException 类型的异常,则把当前捕获到的异常对象继续向上抛出
        throw e;
    }
}
自定义异常

在这里插入图片描述

public class LoginAcctAlreadyInUseForUpdateException extends RuntimeException{
    public LoginAcctAlreadyInUseForUpdateException() {
        super();
    }

    public LoginAcctAlreadyInUseForUpdateException(String message) {
        super(message);
    }

    public LoginAcctAlreadyInUseForUpdateException(String message, Throwable cause) {
        super(message, cause);
    }

    public LoginAcctAlreadyInUseForUpdateException(Throwable cause) {
        super(cause);
    }

    protected LoginAcctAlreadyInUseForUpdateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

在这里插入图片描述

// 修改管理员信息账号已存在异常
@ExceptionHandler(LoginAcctAlreadyInUseForUpdateException.class)
public ModelAndView LoginAcctAlreadyInUseForUpdateException(
          LoginAcctAlreadyInUseForUpdateException exception,
          HttpServletRequest request,
          HttpServletResponse response
  ) throws IOException {
      // 只是指定当前异常对应的页面即可
      String viewName = "system-error";

      return commonResolveException(exception, request, response, viewName);
  }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值