1. 程式人生 > 實用技巧 >尚籌網02管理員維護

尚籌網02管理員維護

任務清單

  • 分頁顯示Admin資料
    •   不帶關鍵詞分頁
    •   帶關鍵詞分頁
  • 新增Admin
  • 更新Admin
  • 單挑刪除Admin

分頁

目標

以分頁的形式把管理員資訊顯示到頁面上.

特殊需求:兼顧關鍵詞查詢,讓後端程式碼不管有沒有查詢條件都能夠以分頁形式顯示資料.

思路

  • 點選使用者維護
    •   跳轉到admin-page.jsp,在頁面初始化的時候把分頁資料也加載出來
  • page頁面查詢關鍵詞的時候,提交給後臺,然後在頁面初始化的時候把分頁資料加載出來
  • 點選上一頁下一頁,把頁面pageNum(keyword)提交給後臺,然後在頁面初始化的時候把分頁資料加載出來

技術點

  • SQL語句針對
    keyword時有時無的情況進行適配
    •   使用SQL中做字串連線的函式:CONCAT(“%”,#{keyword},”%”)
    •   keyword有值:“like %tom%“
    •   Key無值:”like %%“
  • pageHelper使用
    •   引入依賴
    •   在SqlSessionFactoryBean中配置PageHelper
    •   在Java程式碼中使用
      •     PageHelper.startPage(PageNum,PageSize)
      •     PageInfo<Admin> pageInfo = new PageInfo(adminList);
  • 顯示頁碼
    •   使用JQuery外掛:Pagination

後端程式碼

查詢Admin資料的SQL語句

<select id= "selectAdminByKeyword" 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>

準備PageHelper環境

1、匯入座標

<!--mybatis 分頁外掛-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.11</version>
</dependency>

2、配置SqlSessionFactoryBean

<!-- 配置 MyBatis 的外掛 -->
        <property name="plugins">
            <array>
                <!-- 配置 PageHelper -->
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <value>
                            <!-- 分頁外掛會自動檢測當前的資料庫連結,自動選擇合適的分頁方式。 
                            你可以配置helperDialect屬性來指定分頁外掛使用哪種方言。配置時,可以使用下面的縮寫值:
        oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
        特別注意:使用 SqlServer2012 資料庫時,需要手動指定為 sqlserver2012,否則會使用 SqlServer2005 的方式進行分頁。 -->
                            helperDialect=mysql
                            <!-- 預設false禁用 啟用合理化時,如果pageNum<1會查詢第一頁,
                            如果pageNum>pages會查詢最後一頁 禁用合理化時,如果pageNum<1或pageNum>pages會返回空資料 -->
                            reasonable=true
                            <!-- 支援通過 Mapper 介面引數來傳遞分頁引數,預設值false,分頁外掛會從查詢方法的引數值中,自動根據上面 params
        配置的欄位中取值,查詢到合適的值時就會自動分頁。 使用方法可以參考測試程式碼中的 
                                com.github.pagehelper.test.basic
        包下的 ArgumentsMapTest 和 ArgumentsObjTest。 -->
                            supportMethodsArguments=true
                            <!-- 為了支援startPage(Object params)方法,增加了該引數來配置引數對映,
                            用於從物件中根據屬性名取值, 可以配置
        pageNum,pageSize,count,pageSizeZero,reasonable,不配置對映的用預設值,
                                 預設值為pageNum=pageNum;pageSize=pageSize;count=countSql;
                                 reasonable=reasonable;pageSizeZero=pageSizeZero。 -->
                            params=count=countSql
                            <!-- 預設值為 false。設定為 true 時,允許在執行時根據多資料來源自動識別對應方言的分頁 
                            (不支援自動選擇sqlserver2012,只能使用sqlserver)。 -->
                            autoRuntimeDialect=true
                        </value>
                    </property>
                </bean>
            </array>
        </property>

3、AdminService方法

@Override
public PageInfo<Admin> selectAdminByKeyWord(String keyWord, Integer pageNum, Integer pageSize) {
    // 1. 開啟pageHelper的靜態方法,開啟分頁功能
    PageHelper.startPage(pageNum,pageSize);

    // 2. 執行查詢
    List<Admin> admins = adminMapper.selectAdminByKeyWord(keyWord);

    // 3. 封裝到pageInfo物件中
    PageInfo<Admin> pageInfo = PageInfo.of(admins);

    return pageInfo;
}

4、AdminController

@RequestMapping("/admin/get/page.html")
public String getPageInfo(
        //注意:頁面上有可能不提供關鍵詞,要進行匹配
        //@RequestParam註解中設定defaultValue屬性為空字串表示不提供關鍵詞
        @RequestParam(value = "keyword", defaultValue = "") String keyword,
        //預設從第一頁開始
        @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
        @RequestParam(value = "pageSize", defaultValue = "2") Integer pageSize,
        ModelMap modelMap) {

    // 1. 獲取pageInfo
    PageInfo<Admin> adminPageInfo = adminService.selectAdminByKeyWord(keyword, pageNum, pageSize);
    // 2. 將pageInfo存入Model
    modelMap.addAttribute(ConstantUtil.ATTR_NAME_PAGEINFO, adminPageInfo);

    return "/admin-page";
}

5、前端程式碼

根據返回的pageInfo資料,拼接成表進行顯示

<tbody>
<c:if test="${empty requestScope.pageInfo.list}">
    <tr>
        <td colspan="6" align="center"> 抱歉!沒有查詢到你要的資料</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>--%>
                <a href="assign/to/assign/role/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>
                    <%--<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>--%>
                <a href="admin/to/edit/page.html?adminId=${admin.id}&pageNum=${requestScope.pageInfo.pageNum}&keyword=${param.keyword}"
                   class="btn btn-primary btn-xs"><i
                        class=" glyphicon glyphicon-pencil"></i></a>
                <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>
            </td>
        </tr>
    </c:forEach>
</c:if>
</tbody>

6、加入Pagination外掛環境

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh_CN">
<%@include file="/WEB-INF/pages/admincommon/include-head.jsp" %>
<link rel="stylesheet" href="static/css/pagination.css"/>
<script type="text/javascript" src="static/jquery/jquery.pagination.js"></script>
<script type="text/javascript">

7、編寫pagination程式碼

<script type="text/javascript">   
$(
function () { initPagination(); }); //生成分頁導航條函式 function initPagination() { //獲取總記錄數 var totalRecord = ${requestScope.pageInfo.total}; var properties = { num_edge_entries: 3, //邊緣頁數 num_display_entries: 5, //主體頁數 callback: pageselectCallback, items_per_page:${requestScope.pageInfo.pageSize}, //每頁顯示1項 current_page: ${requestScope.pageInfo.pageNum - 1},//Pagination內部使用pageIndex來管理頁面 prev_text: "上一頁", next_text: "下一頁" } // 生成頁碼導航條 $("#Pagination").pagination(totalRecord, properties); } //pageIndex 0- function pageselectCallback(pageIndex, jQuery) { //根據pageIndex計算pageNum var pageNum = pageIndex + 1; //跳轉頁面 window.location.href = "admin/get/page.html?pageNum=" + pageNum + "&keyword=${param.keyword}"; //由於每個按鈕都是超連結,所以這裡取消超連結的預設行為
    //由於會回撥函式,且我們這裡時跳轉頁面,因此會不斷重複
    //解決方法是return false取消預設回撥的行為
return false } </script>

關鍵詞查詢

頁面調整待提交的表單

<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>

翻頁時保持keyword值

//pageIndex 0-
function pageselectCallback(pageIndex, jQuery) {
    //根據pageIndex計算pageNum
    var pageNum = pageIndex + 1;
    //跳轉頁面
    //EL表示式中的param也是一個隱含物件,可以用來獲取請求引數
    window.location.href = "admin/get/page.html?pageNum=" + pageNum + "&keyword=${param.keyword}";
    //由於每個按鈕都是超連結,所以這裡取消超連結的預設行為
    return false;
}

注意:EL表示式中的param是一個隱含的物件,可以用來獲取請求引數.

新增管理員資訊

目標

建立新的管理員資訊,通過表單

思路

程式碼

設定唯一約束

Alter table ‘表名’ add unique index(‘欄位名’)

業務層邏輯

@Override
public void saveAdmin(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 source = admin.getUserPswd();
    String encoded = MD5Util.md5(source);
    admin.setUserPswd(encoded);
    //執行儲存,如果賬號被佔用會丟擲異常
    try{
        adminMapper.insert(admin);
    }catch(Exception e){
        e.printStackTrace();
        //檢測當前捕獲的異常物件,如果是DuplicateKeyException型別說明賬號重複導致
        if (e instanceof DuplicateKeyException){
            //丟擲自定義的LoginAcctAlreadyExist
            throw new LoginAccountAlreadlyInUse(ConstantUtil.MESSAGE_SYSTEM_ERROR_LOGIN_NOT_UNIQUE);
        }
        //如果不是則繼續往上拋
        throw e;
    }
}

異常對映處理器類

當丟擲對應異常時,會被異常攔截器捕捉

@ExceptionHandler(LoginAccountAlreadlyInUse.class)
public ModelAndView resolverLoginAccountAlreadlyInUseException(LoginAccountAlreadlyInUse e, HttpServletRequest request, HttpServletResponse response) throws IOException {
    String viewName = "admin-add";
    ModelAndView modelAndView = common(viewName, e, request, response);
    return modelAndView;
}
/**
 * 提取可複用部分
 * @return
 */
public ModelAndView common(String viewName, Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
    boolean requestType = CrowdUtil.isAjaxRequest(request);
    if (requestType) {
        ResultEntity<Object> failed = ResultEntity.failed(e.getMessage());
        String json = new Gson().toJson(failed);
        response.getWriter().write(json);
        return null;
    } else {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("exception", e);
        modelAndView.setViewName(viewName);
        return modelAndView;
    }
}

自定義異常

控制層

@RequestMapping("/save/admin.html")
public String saveAdmin(Admin admin) {
    //執行儲存
    adminService.saveAdmin(admin);
    // 為了讓使用者第一眼就看到新增加的使用者,直接跳轉到最後一頁
    return "redirect:/admin/page.html?pageNum=" + Integer.MAX_VALUE;
}

儲存之後重定向

"redirect:/admin/page.html?pageNum=" + Integer.MAX_VALUE;

表單頁面

配置跳轉
<mvc:view-controller path="/admin/to/add/page.html" view-name="admin-add"/>

更新刪除管理員資訊

目標

通過提交頁面上的表單修改某個Admin的資料

思路

  • admin-page.jsp頁面點選修改,帶著id到後臺,查詢出對應的admin
  • admin儲存在request
  • 重定向到edit頁面並填充
  • 當點選修改時到後臺執行更新
  • 重定向到page頁面
    •   為了保持所在頁和關鍵詞還需要pageNumkeyword

  • 重定向到main-page.jsp點選刪除(攜帶id)
  • 提交到後臺處理完,重定向到page頁面
    •   什麼時候使用重定向,不需要再返回操作,不需要request的資料

程式碼

<a href="admin/to/edit/page.html?adminId=${admin.id}&pageNum=${requestScope.pageInfo.pageNum}&keyword=${param.keyword}"
   class="btn btn-primary btn-xs"><i
        class=" glyphicon glyphicon-pencil"></i></a>
<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>

controller

@RequestMapping("/admin/to/edit/page.html")
    public String toAdminEdit(@RequestParam("adminId") Integer adminId, ModelMap map) {
        // 1.根據 id(主鍵)查詢待更新的 Admin 物件
        Admin admin = adminService.selectAdminById(adminId);
        // 2.將 Admin 物件存入模型
        map.addAttribute("admin", admin);
        return "admin-edit";
    }
//
    @RequestMapping("/admin/update.html")
    public String editAdmin(Admin admin,
                            @RequestParam("pageNum") Integer pageNum,
                            @RequestParam("keyword") String keyword,
                            ModelMap map) {

        adminService.updateAdmin(admin);
        return "redirect:/admin/get/page.html?pageNum=" + pageNum + "&keyword=" + keyword;
    }
@RequestMapping("/admin/remove/{id}/{pageNum}/{keyword}")
public String deleteAdmin(@PathVariable("id") Integer id,
                          @PathVariable("pageNum") Integer pageNum,
                          @PathVariable(value = "keyword") String keyword) {
    adminService.deleteAdminByPrimaryKey(id);

    return "redirect:/admin/get/page.html?pageNum=" + pageNum + "&keyword=" + keyword;
}

service

@Override
public void deleteAdminByPrimaryKey(Integer id) {
    adminMapper.deleteByPrimaryKey(id);
}

@Override
public Admin selectAdminById(Integer adminId) {
    Admin admin = adminMapper.selectByPrimaryKey(adminId);
    return admin;
}

@Override
public void updateAdmin(Admin admin) {

    try {
        adminMapper.updateByPrimaryKeySelective(admin);
    } catch (Exception e) {
        if (e instanceof DuplicateKeyException) {
            throw new LoginAccountAlreadlyInUseForUpdate("不允許重複的賬戶");
        }
    }
}