直接上代碼,原理以前的隨筆已經講過了。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!