DataTables合併單元格(rowspan)的實現思路(多分組分類的狀況)

直接上代碼,原理以前的隨筆已經講過了。http://www.cnblogs.com/hdwang/p/7115835.htmljavascript

1.先看看效果css

 

 

2.html代碼,含js代碼html

2.1 common.js前端

/**
 * Created by hdwang on 2017/6/23.
 */
var language = { "search": "", "sSearch" : "搜索", "sUrl" : "", "sProcessing" : "正在加載數據...", "sLengthMenu" : "顯示_MENU_條 ", "sZeroRecords" : "沒有您要搜索的內容",
    "sInfo" : "從_START_ 到 _END_ 條記錄——總記錄數爲 _TOTAL_ 條", "sInfoEmpty" : "記錄數爲0", "sInfoFiltered" : "(所有記錄數 _MAX_  條)", "sInfoPostFix" : "",
    "oPaginate": { "sFirst" : "第一頁", "sPrevious" : " 上一頁 ", "sNext" : " 下一頁 ", "sLast" : " 最後一頁 " }
};

/**
 * 將參數對象轉換成url查詢參數
 * @param params 參數對象
 * @returns {string} url查詢參數
 */
function getUrlParams(params) {
    var queryStr = '';
    var isFirstParam = true;
    for(var key in params){
        if(isFirstParam){
            queryStr += key + '=' + params[key];
            isFirstParam = false;
        }else{
            queryStr += '&' + key + '=' + params[key];
        }
    }
    return queryStr;
}

 

2.2 home.ftljava

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! -->
    <title>cpm system</title>

    <!-- Bootstrap -->
    <link href="/thirdlib/bootstrap/css/bootstrap.min.css" rel="stylesheet">

    <!-- datatables -->
    <link href="/thirdlib/datatables/css/jquery.dataTables.min.css" rel="stylesheet"/>

    <link href="/css/common.css" rel="stylesheet" />
</head>
<body>


<div id="tableArea" style="padding: 100px;">
<div>
<a href="/home/export">導出</a>
</div>

<table id="rowspanTable" class="table table-bordered"> <thead> <th>地區</th> <th>公司</th> <th>部門</th> <th>員工姓名</th> </thead> </table> </div> </body> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="/thirdlib/jquery/jquery-2.0.3.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="/thirdlib/bootstrap/js/bootstrap.min.js"></script> <!-- datatables --> <script src="/thirdlib/datatables/js/jquery.dataTables.min.js"></script> <script src="/js/common.js"></script> <script type="text/javascript"> $(function(){ $('#rowspanTable').dataTable( { "paging": true, "processing": true, "serverSide": true, "searching":false, //搜索欄 "lengthChange" : false, //是否容許改變每頁顯示的數據條數 "pageLength": 10, //每行顯示記錄數 "info":true, //開啓Datatables信息顯示(記錄數等) "ordering":false, //全局定義是否啓用排序,優先級比columns.orderable高 "language": language, "ajax": { "url": "/home/query", "type": "POST" }, "columns": [ {"data":"area", "orderable": false,"searchable": false}, { "data": "company", "orderable": false ,"searchable": false}, { "data": "department", "orderable": false,"searchable": false }, { "data": "userName", "orderable": false ,"searchable": false} ], "columnDefs": [{ targets: [0,1,2], //第1,2,3列 createdCell: function (td, cellData, rowData, row, col) { var rowspan = 1; if(col == 0){ rowspan = rowData.areaRowSpan; } if(col ==1){ rowspan = rowData.companyRowSpan; } if(col ==2){ rowspan = rowData.departmentRowSpan; } if (rowspan > 1) { $(td).attr('rowspan', rowspan) } if (rowspan == 0) { $(td).remove(); } } }] } ); }); </script> </html>

 

3.後臺代碼mysql

3.1 分頁參數對象jquery

package com.xincheng.cpm.common;

/**
 * Created by hdwang on 2017/6/22.
 * 分頁參數
 */
public class PageParam {

    /**
     * 第幾回繪畫(前端標識)
     */
    private int draw;

    /**
     * 起始記錄(從0開始),mysql也是從0開始,吻合,good!
     */
    private int start;

    /**
     * 頁大小
     */
    private int length;

    public int getDraw() {
        return draw;
    }

    public void setDraw(int draw) {
        this.draw = draw;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    /**
     * 第幾頁(0-n)
     */
    public int getPage(){
        return this.start/this.length;
    }
}

 

3.2 數據返回對象web

package com.xincheng.cpm.common;

import java.util.List;

/**
 * Created by hdwang on 2017/6/22.
 * 表格數據(datatables)
 */
public class TableData<T> {

    /**
     * 第幾回繪畫(前端標識)
     */
    private int draw;

    /**
     * 行過濾(不知道幹嗎的)
     */
    private int recordsFiltered;

    /**
     * 總行數
     */
    private int recordsTotal;

    /**
     * 行數據
     */
    private List<T> data;

    /**
     * 起始記錄(用於前端初始化序列號用的)
     */
    private int start;

    /**
     *  錯誤信息
     */
    private String error;

    public int getDraw() {
        return draw;
    }

    public void setDraw(int draw) {
        this.draw = draw;
    }

    public int getRecordsFiltered() {
        return recordsFiltered;
    }

    public void setRecordsFiltered(int recordsFiltered) {
        this.recordsFiltered = recordsFiltered;
    }

    public int getRecordsTotal() {
        return recordsTotal;
    }

    public void setRecordsTotal(int recordsTotal) {
        this.recordsTotal = recordsTotal;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }
}

 

 3.3 數據實體對象ajax

package com.xincheng.cpm.common;

import java.io.Serializable;

/**
 * Created by hdwang on 2017/7/14.
 */
public class Member{

    private String area;
    private String company;
    private String department;
    private String userName;

    private Integer areaRowSpan;
    private Integer companyRowSpan;
    private Integer departmentRowSpan;


    public Member(String area,String company,String department,String userName){
        this.area = area;
        this.company = company;
        this.department = department;
        this.userName = userName;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public String getUserName() {
        return userName;
    }

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

    public Integer getAreaRowSpan() {
        return areaRowSpan;
    }

    public void setAreaRowSpan(Integer areaRowSpan) {
        this.areaRowSpan = areaRowSpan;
    }

    public Integer getCompanyRowSpan() {
        return companyRowSpan;
    }

    public void setCompanyRowSpan(Integer companyRowSpan) {
        this.companyRowSpan = companyRowSpan;
    }

    public Integer getDepartmentRowSpan() {
        return departmentRowSpan;
    }

    public void setDepartmentRowSpan(Integer departmentRowSpan) {
        this.departmentRowSpan = departmentRowSpan;
    }
}

 

3.4 導出相關類spring

package com.xincheng.cpm.common;

/**
 * Created by hdwang on 2017/7/14.
 */
public class ExcelData {
    private String value;//單元格的值
    private int colSpan = 1;//單元格跨幾列
    private int rowSpan = 1;//單元格跨幾行
    private boolean alignCenter;//單元格是否居中,默認不居中,若是選擇是,則水平和上下都居中
    public boolean isAlignCenter() {
        return alignCenter;
    }
    public void setAlignCenter(boolean alignCenter) {
        this.alignCenter = alignCenter;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    public int getColSpan() {
        return colSpan;
    }
    public void setColSpan(int colSpan) {
        this.colSpan = colSpan;
    }
    public int getRowSpan() {
        return rowSpan;
    }
    public void setRowSpan(int rowSpan) {
        this.rowSpan = rowSpan;
    }
}
package com.xincheng.cpm.common;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.util.List;

/**
 * Created by hdwang on 2017/7/14.
 */
public class ExcelUtil {


    /**
     * 生成excel工做簿
     * @param sheetTitle sheet名稱
     * @param titles 標題
     * @param rows 行數據
     * @return 工做簿
     */
    public XSSFWorkbook execute(String sheetTitle,String[] titles,List<List<ExcelData>> rows) {
        //定義工做簿
        XSSFWorkbook workbook = new XSSFWorkbook();

        //th樣式
        CellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setBorderBottom((short) 1);
        titleStyle.setBorderRight((short)1);
        titleStyle.setBorderLeft((short)1);
        titleStyle.setBorderTop((short)1);
        titleStyle.setVerticalAlignment((short)1);
        titleStyle.setAlignment((short)2);
        XSSFFont font = workbook.createFont();
        font.setBold(true);
        titleStyle.setFont(font);
        //td樣式
        CellStyle style = workbook.createCellStyle();
        style.setBorderBottom((short)1);
        style.setBorderRight((short)1);
        style.setBorderLeft((short)1);
        style.setBorderTop((short)1);
        style.setVerticalAlignment((short)1);

        //建立工做表
        XSSFSheet sheet = workbook.createSheet(sheetTitle);
        sheet.setDefaultRowHeightInPoints(20.0F);

        //建立標題行
        XSSFRow titleRow = sheet.createRow(0);


        for(int col=0;col<titles.length;col++) { //遍歷列
            Cell cell = titleRow.createCell(col);
            cell.setCellStyle(titleStyle);
            cell.setCellValue(titles[col]);

            for(int row=0;row<rows.size();row++){ //遍歷行
                int rowIndex = row+1;
                XSSFRow contentRow = sheet.getRow(rowIndex);
                if(contentRow == null){
                    contentRow = sheet.createRow(rowIndex);
                }
                ExcelData data = rows.get(row).get(col);
                Cell contentRowCell = contentRow.createCell(col);
                contentRowCell.setCellStyle(style);
                contentRowCell.setCellValue(data.getValue());
                //合併單元格
                if (data.getColSpan() > 1 || data.getRowSpan() > 1) {
                    CellRangeAddress cra = new CellRangeAddress(rowIndex, rowIndex + data.getRowSpan() - 1, col, col + data.getColSpan() - 1);
                    sheet.addMergedRegion(cra);
                }
            }
        }

        return workbook;
    }
}

 

 

3.5 controller層

package com.xincheng.cpm.controller;

import com.chenrd.common.excel.ExportExcel;
import com.xincheng.cpm.common.*;
import com.xincheng.cpm.entity.cpm.User;
import com.xincheng.cpm.service.UserService;
import com.xincheng.cpm.vo.IncomeDailyVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;

/**
 * Created by hdwang on 2017/6/19.
 */
@Controller
@RequestMapping("/home")
public class HomeController {

    @Autowired
    UserService userService;

    @RequestMapping("")
    public String index(HttpSession session, ModelMap map, HttpServletRequest request){
        User user = (User) session.getAttribute("user");
        map.put("user",user);
        return "home";
    }


    @RequestMapping(value="/query",method= RequestMethod.POST)
    @ResponseBody
    public TableData<Member> getUserByPage(PageParam pageParam, User user){
        Page<Member> userPage = this.getMembers(pageParam);
        TableData<Member> datas = new TableData<>();
        datas.setDraw(pageParam.getDraw());
        datas.setStart(pageParam.getStart());
        datas.setData(userPage.getContent());
        datas.setRecordsFiltered((int)userPage.getTotalElements());
        datas.setRecordsTotal((int)userPage.getTotalElements());
        return datas;
    }

    private Page<Member> getMembers(PageParam pageParam) {
        //1.模擬數據庫查詢
        Pageable pageable = new PageRequest(pageParam.getPage(), pageParam.getLength());
        long count = 6;
        List<Member> members = getMembersFromDb();

        //2.計算rowspan
        this.countRowspan(members);


        Page<Member> memberPage = new PageImpl<Member>(members,pageable,count);
        return memberPage;
    }

    private void countRowspan(List<Member> members) {
        Map<String,Integer> propertyCountMap = this.countPropertyCount(members);
        List<String> hadGetKeys = new ArrayList<>(); //曾經取過的key
        for(Member member:members){
            String areaKey = member.getArea();
            String companyKey = areaKey+member.getCompany();
            String departmentKey = companyKey+ member.getDepartment();

            Integer areaCount = propertyCountMap.get(areaKey);
            if(areaCount == null){
                member.setAreaRowSpan(1);
            }else{
                if(hadGetKeys.contains(areaKey)){
                    member.setAreaRowSpan(0); //曾經取過
                }else{
                    member.setAreaRowSpan(areaCount); //第一次取
                    hadGetKeys.add(areaKey);
                }
            }

            Integer companyCount = propertyCountMap.get(companyKey);
            if(companyCount == null){
                member.setCompanyRowSpan(1);
            }else {
                if(hadGetKeys.contains(companyKey)){
                    member.setCompanyRowSpan(0);
                }else{
                    member.setCompanyRowSpan(companyCount);
                    hadGetKeys.add(companyKey);
                }
            }

            Integer departmentCount = propertyCountMap.get(departmentKey);
            if(companyCount == null){
                member.setDepartmentRowSpan(1);
            }else {
                if(hadGetKeys.contains(departmentKey)){
                    member.setDepartmentRowSpan(0);
                }else{
                    member.setDepartmentRowSpan(departmentCount);
                    hadGetKeys.add(departmentKey);
                }
            }
        }
    }

    private List<Member> getMembersFromDb() {
        Member member1 = new Member("安徽","A","人力資源部"," 小紅");
        Member member2 = new Member("安徽","B","人力資源部"," 小明");
        Member member3 = new Member("浙江","C","人力資源部"," 小君");
        Member member4 = new Member("浙江","C","技術部"," 小王");
        Member member5 = new Member("浙江","D","技術部"," 小李");
        Member member6 = new Member("浙江","D","人力資源部"," 小剛");
        List<Member> members = new ArrayList<>();
        members.add(member1);
        members.add(member2);
        members.add(member3);
        members.add(member4);
        members.add(member5);
        members.add(member6);
        return members;
    }

    /**
     * 統計每一個字段的每組成員個數
     * @param rows  記錄
     * @return 每一個字段的每組成員個數
     */
    private Map<String,Integer> countPropertyCount(List<Member> rows){

        Map<String,Integer> propertyCountMap = new HashMap<>();

        for(Member member:rows){
            // "area": 無父級分組
            String area = member.getArea();
            if(propertyCountMap.get(area) == null){
                propertyCountMap.put(area,1);
            }else{
                int count = propertyCountMap.get(area);
                propertyCountMap.put(area,count+1);
            }

            // "company":有area父組
            String company = member.getCompany();
            String uniqueParent = member.getArea();
            String key = uniqueParent + company;
            if(propertyCountMap.get(key) == null){
                propertyCountMap.put(key,1);
            }else{
                int count = propertyCountMap.get(key);
                propertyCountMap.put(key,count+1);
            }

            // "department": 有area,company這兩個父組
            String department = member.getDepartment();
            uniqueParent = member.getArea()+member.getCompany();
            key = uniqueParent + department;
            if(propertyCountMap.get(key) == null){
                propertyCountMap.put(key,1);
            }else{
                int count = propertyCountMap.get(key);
                propertyCountMap.put(key,count+1);
            }
        }

        return propertyCountMap;
    }


    @RequestMapping("/export")
    public void export(HttpServletResponse response) throws IOException {
        List<Member> members = this.getMembersFromDb();
        this.countRowspan(members);

        List<List<ExcelData>> rows = new ArrayList<>();
        for(Member member:members){
            List<ExcelData> row = new ArrayList<>();
            ExcelData col1 = new ExcelData();
            col1.setValue(member.getArea());
            col1.setRowSpan(member.getAreaRowSpan());
            row.add(col1);

            ExcelData col2 = new ExcelData();
            col2.setValue(member.getCompany());
            col2.setRowSpan(member.getCompanyRowSpan());
            row.add(col2);

            ExcelData col3 = new ExcelData();
            col3.setValue(member.getDepartment());
            col3.setRowSpan(member.getDepartmentRowSpan());
            row.add(col3);

            ExcelData col4 = new ExcelData();
            col4.setValue(member.getUserName());
            row.add(col4);

            rows.add(row);
        }

        OutputStream outputStream = response.getOutputStream();
        try {
            String filename = URLEncoder.encode("員工" + ".xlsx", "UTF-8");
            response.setContentType("application/vnd.ms-excel");
            response.addHeader("Content-Disposition", "octet-stream;filename=" + filename);

            ExcelUtil excelUtil = new ExcelUtil();
            XSSFWorkbook workbook = excelUtil.execute("sheet1",new String[]{"地區","公司","部門","員工姓名"},rows);
            workbook.write(outputStream);
        } finally {
            if (outputStream != null) outputStream.close();
        }
    }




}

導出excel功能使用poi類庫實現。至此,頁面展現和導出均OK!

相關文章
相關標籤/搜索