天天看點

SpringMVC+Spring+MyBatis 的綜合練習 12 (針對分頁的 MVC)

MVC 模式在實作的過程中分了 DAO,Service,Controller 和 View 幾個層面。先抄一段很多部落格都引用的關于各層的解釋。

  • DAO層

    DAO層主要是做資料持久層的工作,負責與資料庫進行聯絡的一些任務都封裝在此,DAO層的設計首先是設計DAO的接口,然後在Spring的配置檔案中定義此接口的實作類,然後就可在子產品中調用此接口來進行資料業務的處理,而不用關心此接口的具體實作類是哪個類,顯得結構非常清晰,DAO層的資料源配置,以及有關資料庫連接配接的參數都在Spring的配置檔案中進行配置。

    DAO設計的總體規劃需要和設計的表,和實作類之間一一對應。

    DAO層所定義的接口裡的方法都大同小異,這是由我們在DAO層對資料庫通路的操作來決定的,對資料庫的操作,我們基本要用到的就是新增,更新,删除,查詢等方法。因而DAO層裡面基本上都應該要涵蓋這些方法對應的操作。除此之外,可以定義一些自定義的特殊的對資料庫通路的方法。

  • Service層

    Service層主要負責業務子產品的邏輯應用設計。同樣是首先設計接口,再設計其實作的類,接着再Spring的配置檔案中配置其實作的關聯。這樣我們就可以在應用中調用Service接口來進行業務處理。Service層的業務實作,具體要調用到已定義的DAO層的接口,封裝Service層的業務邏輯有利于通用的業務邏輯的獨立性和重複利用性,程式顯得非常簡潔。

    Service層是建立在DAO層之上的,建立了DAO層後才可以建立Service層,而Service層又是在Controller層之下的,因而Service層應該既調用DAO層的接口,又要提供接口給Controller層的類來進行調用,它剛好處于一個中間層的位置。每個模型都有一個Service接口,每個接口分别封裝各自的業務處理方法。

    在DAO層定義的一些方法,在Service層并沒有使用,那為什麼還要在DAO層進行定義呢?這是由我們定義的需求邏輯所決定的。DAO層的操作 經過抽象後基本上都是通用的,因而我們在定義DAO層的時候可以将相關的方法定義完畢,這樣的好處是在對Service進行擴充的時候不需要再對DAO層進行修改,提高了程式的可擴充性。

  • Controller層

    Controller層負責具體的業務子產品流程的控制,在此層裡面要調用Serice層的接口來控制業務流程,控制的配置也同樣是在Spring的配置檔案裡面進行,針對具體的業務流程,會有不同的控制器,我們具體的設計過程中可以将流程進行抽象歸納,設計出可以重複利用的子單元流程子產品,這樣不僅使程式結構變得清晰,也大大減少了代碼量。

  • View層

    此層與控制層結合比較緊密,需要二者結合起來協同工發。

    View層主要負責前台jsp頁面的表示。

  • 開發側重

    DAO層,Service層這兩個層次都可以單獨開發,互相的耦合度很低,完全可以獨立進行,這樣的一種模式在開發大項目的過程中尤其有優勢。本項目雖然是個非常小的練習項目,但依然采用了這種模式。這樣做既可以建立和鞏固MVC分層設計的理念和習慣,同時在遇到大項目的時候不至于對此茫然到一無所知而無從下手。隻不過因為項目小而使得 Service 中幾乎沒有更多的内容,單純調用了 DAO 的接口罷了。如果有較為複雜的查詢統計任務,直接用DAO的接口操作看起來會讓程式的靈活性和擴充性變差,而且DAO更多的是面向單個實體類,多個實體類的同時操作(如彙款:修改兩個賬戶的餘額并記錄兩條收支明細),在 Service 層就需要分别調用不同的方法去完成了。

    Controller,View層因為耦合度比較高,因而要結合在一起開發,但是也可以看作一個整體獨立于前兩個層進行開發。這樣,在層與層之前我們隻需要知道接口的定義,調用接口即可完成所需要的邏輯單元應用,一切都顯得非常清晰簡單。實踐中,我發現的确 Controller 更關注于對頁面的請求,傳遞參數給後面的 Service 層以及将傳回的結果再交還給頁面。

下面以 Employee 實體為例,列出四層的設計代碼。

12.1 DAO 層

EmployeeMapper.java 代碼

package com.hh.ssm.dao;

import com.hh.ssm.bean.Employee;
import com.hh.ssm.bean.EmployeeExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
/**
 * 定義了 DAO接口,其中的方法最終實際上是由 MyBatis 負責實作的。
 * @author HH
 */

public interface EmployeeMapper {
    long countByExample(EmployeeExample example);

    int deleteByExample(EmployeeExample example);

    int deleteByPrimaryKey(Integer employeeId);

    int insert(Employee record);

    int insertSelective(Employee record);

    List<Employee> selectByExample(EmployeeExample example);

    Employee selectByPrimaryKey(Integer employeeId);

    List<Employee> selectByExampleWithDepartment(EmployeeExample example);

    Employee selectByPrimaryKeyWithDepartment(Integer employeeId);

    int updateByExampleSelective(@Param("record") Employee record, @Param("example") EmployeeExample example);

    int updateByExample(@Param("record") Employee record, @Param("example") EmployeeExample example);

    int updateByPrimaryKeySelective(Employee record);

    int updateByPrimaryKey(Employee record);
}
           

12.2 Service 層

EmployeeService.java 代碼如下:

目前暫時隻是寫了一個業務:擷取全部員工資訊。

package com.hh.ssm.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.hh.ssm.bean.Employee;
import com.hh.ssm.dao.EmployeeMapper;

@Service
public class EmployeeService {

    @Autowired
    EmployeeMapper employeeMapper;

    // 擷取全部員工資訊。
    public List<Employee> getAll() {
        return employeeMapper.selectByExampleWithDepartment(null);
    }
}
           

12.3 Controller 層

EmployeeController.java 代碼如下:

package com.hh.ssm.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hh.ssm.bean.Employee;
import com.hh.ssm.service.EmployeeService;

@Controller
public class EmployeeController {

    @Autowired
    EmployeeService employeeService;

    /**
     * 查詢員工資料(分頁查詢)
     * 
     * @return
     */
    @RequestMapping("/employees")
    public String getAllEmployees(
            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum, 
            Model model) {

        // 引入PageHelper分頁插件進行分頁
        // 每頁的記錄數
        int pageSize = ;
        // 傳遞分頁參數
        PageHelper.startPage(pageNum, pageSize);
        // startPage 後面的第一個查詢,結果會分頁
        List<Employee> employees = employeeService.getAll();
        // 導航頁碼數量
        int navigatePages = ;
        // 将分頁結果封裝到 PageInfo        
        PageInfo pageInfo = new PageInfo(employees, navigatePages);
        //System.out.println(pageInfo);
        // 把 PageInfo 封裝到 model,傳回到傳回頁面 
        model.addAttribute("pageInfo", pageInfo);       
        // 傳回的頁面,根據dispatcher配置中,應該調用的是 /WEB-INF/view/employees.jsp
        return "employees";
    }
}
           

12.4 View層

這層是jsp,我先把傳回的頁面貼出來,下一篇總結這個是怎麼來的。

/ssm/src/main/webapp/WEB-INF/views/employees.jsp 的代碼如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 引入JSTL -->
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!--  
<link rel="stylesheet"
    href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" target="_blank" rel="external nofollow" >
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script
    src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
-->
<%
    pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<link rel="stylesheet"
    href="${APP_PATH }/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<script src="${APP_PATH }/static/js/jquery-1.12.4.min.js"></script>
<script
    src="${APP_PATH }/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
<title>員工清單</title>

</head>

<body>
    <div class="container">
        <h1 class="page-header">員工管理</h1>
        <div class="row">
            <h3 class="page-header col-md-10">員工清單</h3>
            <button class="page-header col-sd-1 btn btn-info">
                <span class="glyphicon glyphicon-plus"></span> 新增
            </button>
            <button class="page-header col-sd-1 btn btn-danger">
                <span class="glyphicon glyphicon-trash"></span> 删除
            </button>
        </div>

        <br>
        <div class="row">
            <table class="table table-striped table-hover">
                <thead>
                    <tr>
                        <th class="col-md-1">#</th>
                        <th class="col-md-1">部門名稱</th>
                        <th class="col-md-1">員工姓名</th>
                        <th class="col-md-1">性别</th>
                        <th class="col-md-2">電子郵箱</th>
                        <th class="col-md-2">建立時間</th>
                        <th class="col-md-2">更新時間</th>
                        <th class="col-md-2">操作</th>
                    </tr>
                </thead>
                <tbody>
                    <c:forEach items="${pageInfo.list }" var="employee">
                        <tr>
                            <td class="col-md-1" style="vertical-align: middle;">${employee.employeeId }</td>
                            <td class="col-md-1" style="vertical-align: middle;">${employee.department.departmentName }</td>
                            <td class="col-md-1" style="vertical-align: middle;">${employee.employeeName }</td>
                            <td class="col-md-1" style="vertical-align: middle;">${employee.employeeGender }</td>
                            <td class="col-md-2" style="vertical-align: middle;">${employee.employeeEmail }</td>
                            <td class="col-md-2" style="vertical-align: middle;"><fmt:formatDate
                                    value="${employee.gmtCreate }" pattern="yyyy-MM-dd" /></td>
                            <td class="col-md-2" style="vertical-align: middle;"><fmt:formatDate
                                    value="${employee.gmtModified }" pattern="yyyy-MM-dd" /></td>
                            <td class="col-md-2" style="vertical-align: middle;">
                                <button class="btn btn-primary btn-xs">
                                    <span class="glyphicon glyphicon-pencil"></span> 編輯
                                </button>
                                <button class="btn btn-danger btn-xs">
                                    <span class="glyphicon glyphicon-trash"></span> 删除
                                </button>
                            </td>
                        </tr>
                    </c:forEach>

                    <tr>
                        <td style="vertical-align: middle;" colspan="5" class="col-md-6">目前 第
                            ${pageInfo.pageNum } 頁,共 ${pageInfo.pages } 頁,共有 ${pageInfo.total }
                            條記錄。</td>
                        <td style="vertical-align: middle;" colspan="3" class="col-md-6" align="right">
                            <nav aria-label="Page navigation">
                                <ul class="pagination pagination">
                                    <li><a href="${APP_PATH }/employees?pageNum=1">首頁</a></li>
                                    <c:if test="${pageInfo.hasPreviousPage }">
                                        <li><a
                                            href="${APP_PATH }/employees?pageNum=${pageInfo.pageNum-1 }"
                                            aria-label="Previous"> <span aria-hidden="true">&laquo;</span></a></li>
                                    </c:if>
                                    <c:forEach items="${pageInfo.navigatepageNums }"
                                        var="navigatePageNum">
                                        <c:if test="${navigatePageNum == pageInfo.pageNum }">

                                            <li class="active"><a href="#">${navigatePageNum } <span
                                                    class="sr-only">(current)</span></a></li>
                                        </c:if>
                                        <c:if test="${navigatePageNum != pageInfo.pageNum }">
                                            <li><a
                                                href="${APP_PATH }/employees?pageNum=${navigatePageNum }">${navigatePageNum }</a></li>
                                        </c:if>

                                    </c:forEach>
                                    <c:if test="${pageInfo.hasNextPage }">
                                        <li><a
                                            href="${APP_PATH }/employees?pageNum=${pageInfo.pageNum+1 }"
                                            aria-label="Next"> <span aria-hidden="true">&raquo;</span>
                                        </a></li>
                                    </c:if>
                                    <li><a
                                        href="${APP_PATH }/employees?pageNum=${pageInfo.pages }">末頁</a></li>
                                </ul>
                            </nav>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>

</body>

</html>
           

繼續閱讀