第一步添加依賴
<dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-spring-boot-starter</artifactId> <version>4.1.3</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-scratchpad --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> </dependency>
創建實體
DrillingDaily 注解@Excel表示需要導出那個字段,默認將其全部導出,不需要導出哪個列是,將注解
注解@Excel的值改為空字符串,就可以根據傳入的表頭信息靈活導出excel
package com.shiwen.jdzx.model.daily; import cn.afterturn.easypoi.excel.annotation.Excel; /** * <p>Title:DrillingDaily </p> * <p>Description: 鑽井日報</p> * <p>Company:西安石文軟件有限公司 </p> * * @author liuguiyuan * @date 2019/9/4 14:04 */ public class DrillingDaily { /** * 鑽井日報 * jh:井號;ktgs:勘探公司;jd:井隊;rq:日期 * sjjs:設計井深;drjs:當日井深;jc:進尺 * ztcc:鑽頭尺寸;ztxh:鑽頭型號;cw:層位 * gcjk:工程簡況;zy:鑽壓;zs:轉速;by2:泵壓 * pl:排量;md:密度;nd:粘度;ss:失水;cz:純鑽 * gj:固井;sc:生產;fz:復雜;sg:事故 * xl:修理;tg:停工;qt:其他;bz:備注 */ @Excel(name = "井號") private String jh; @Excel(name = "勘探公司") private String ktgs; @Excel(name = "井隊") private String jd; @Excel(name = "日期") private String rq; @Excel(name = "設計井深") private Double sjjs; @Excel(name = "當日井深") private Double drjs; @Excel(name = "進尺") private Double jc; @Excel(name = "鑽頭尺寸") private Double ztcc; @Excel(name = "鑽頭型號") private String ztxh; @Excel(name = "層位") private String cw; @Excel(name = "工程簡況") private String gcjk; @Excel(name = "鑽壓") private String zy; @Excel(name = "轉速") private String zs; @Excel(name = "泵壓") private String by2; @Excel(name = "排量") private String pl; @Excel(name = "密度") private String md; @Excel(name = "粘度") private String nd; @Excel(name = "失水") private String ss; @Excel(name = "純鑽") private Double cz; @Excel(name = "固井") private Double gj; @Excel(name = "生產") private Double sc; @Excel(name = "復雜") private Double fz; @Excel(name = "事故") private Double sg; @Excel(name = "修理") private Double xl; @Excel(name = "停工") private Double tg; @Excel(name = "其他") private String qt; @Excel(name = "備注") private String bz; public String getJh() { return jh; } public void setJh(String jh) { this.jh = jh; } public String getKtgs() { return ktgs; } public void setKtgs(String ktgs) { this.ktgs = ktgs; } public String getJd() { return jd; } public void setJd(String jd) { this.jd = jd; } public String getRq() { return rq; } public void setRq(String rq) { this.rq = rq; } public Double getSjjs() { return sjjs; } public void setSjjs(Double sjjs) { this.sjjs = sjjs; } public Double getDrjs() { return drjs; } public void setDrjs(Double drjs) { this.drjs = drjs; } public Double getJc() { return jc; } public void setJc(Double jc) { this.jc = jc; } public Double getZtcc() { return ztcc; } public void setZtcc(Double ztcc) { this.ztcc = ztcc; } public String getZtxh() { return ztxh; } public void setZtxh(String ztxh) { this.ztxh = ztxh; } public String getCw() { return cw; } public void setCw(String cw) { this.cw = cw; } public String getGcjk() { return gcjk; } public void setGcjk(String gcjk) { this.gcjk = gcjk; } public String getZy() { return zy; } public void setZy(String zy) { this.zy = zy; } public String getZs() { return zs; } public void setZs(String zs) { this.zs = zs; } public String getBy2() { return by2; } public void setBy2(String by2) { this.by2 = by2; } public String getPl() { return pl; } public void setPl(String pl) { this.pl = pl; } public String getMd() { return md; } public void setMd(String md) { this.md = md; } public String getNd() { return nd; } public void setNd(String nd) { this.nd = nd; } public String getSs() { return ss; } public void setSs(String ss) { this.ss = ss; } public Double getCz() { return cz; } public void setCz(Double cz) { this.cz = cz; } public Double getGj() { return gj; } public void setGj(Double gj) { this.gj = gj; } public Double getSc() { return sc; } public void setSc(Double sc) { this.sc = sc; } public Double getFz() { return fz; } public void setFz(Double fz) { this.fz = fz; } public Double getSg() { return sg; } public void setSg(Double sg) { this.sg = sg; } public Double getXl() { return xl; } public void setXl(Double xl) { this.xl = xl; } public Double getTg() { return tg; } public void setTg(Double tg) { this.tg = tg; } public String getQt() { return qt; } public void setQt(String qt) { this.qt = qt; } public String getBz() { return bz; } public void setBz(String bz) { this.bz = bz; } }
編寫修改@excel注解值的工具類
ModifyAnnotationValues
1 package com.shiwen.jdzx.server.util; 2 3 import cn.afterturn.easypoi.excel.annotation.Excel; 4 import cn.afterturn.easypoi.excel.annotation.ExcelCollection; 5 import cn.afterturn.easypoi.excel.annotation.ExcelEntity; 6 import lombok.extern.slf4j.Slf4j; 7 8 import java.lang.reflect.*; 9 import java.util.List; 10 import java.util.Map; 11 12 /** 13 * @company: 石文軟件有限公司 14 * @description 15 * @author: wangjie 16 * @create: 2020-01-10 11:17 17 **/ 18 @Slf4j 19 public class ModifyAnnotationValues { 20 21 /** 22 * * 修改fields上@Excel注解的name屬性,不需要下載的列,name修改增加_ignore. 23 * * 保存原來的@Excel注解name屬性值,本次生成后用來恢復 24 * * @Params 25 * * headers:用戶勾選,由前端傳來的列名,列名的key必須和Model字段對應 26 * * clazz:model實體類 27 * * excelMap:用來記錄原值的map,因為用到了遞歸,這里返回值作為參數傳入 28 * * @return Map<String, String> 原實體類字段名和@Excel注解name屬性值的映射關系<字段名,@Excel注解name屬性值> 29 * 30 */ 31 public static Map<String, String> dynamicChangeAndSaveSourceAnnotation(List<String> headers, Class clazz, Map<String, String> excelMap) { 32 Field[] fields = clazz.getDeclaredFields(); 33 for (Field field : fields) { 34 // @Excel注解 35 if (field.isAnnotationPresent(Excel.class)) { 36 boolean flag = true; 37 for (int i = 0; i < headers.size(); i++) { 38 String header = headers.get(i); 39 if (field.getName().equals(header)) { 40 flag = false; 41 break; 42 } 43 } 44 // 下載列不包括該字段,進行隱藏,並記錄原始值 45 if (flag) { 46 Excel annotation = field.getAnnotation(Excel.class); 47 // 保存注解 48 excelMap.put(field.getName(), annotation.name()); 49 InvocationHandler handler = Proxy.getInvocationHandler(annotation); 50 String value = annotation.name().toString(); 51 changeAnnotationValue(handler, " "); 52 } 53 // @ExcelCollection注解 54 } else if (field.isAnnotationPresent(ExcelCollection.class) && field.getType().isAssignableFrom(List.class)) { 55 Type type = field.getGenericType(); 56 if (type instanceof ParameterizedType) { 57 ParameterizedType pt = (ParameterizedType) type; 58 Class collectionClazz = (Class) pt.getActualTypeArguments()[0]; 59 // 解決@ExcelCollection如果沒有需要下載列的異常,java.lang.IllegalArgumentException: The 'to' col (15) must not be less than the 'from' col (16) 60 // 如果沒有需要下載列,將@ExcelCollection忽略 61 Field[] collectionFields = collectionClazz.getDeclaredFields(); 62 boolean flag = false; 63 out: 64 for (Field temp : collectionFields) { 65 if (!temp.isAnnotationPresent(Excel.class)) { 66 continue; 67 } 68 for (int i = 0; i < headers.size(); i++) { 69 String header = headers.get(i); 70 if (temp.getName().equals(header)) { 71 flag = true; 72 break out; 73 } 74 } 75 } 76 if (flag) { 77 dynamicChangeAndSaveSourceAnnotation(headers, collectionClazz, excelMap); 78 } else { 79 ExcelCollection annotation = field.getAnnotation(ExcelCollection.class); 80 excelMap.put(field.getName(), annotation.name()); 81 InvocationHandler handler = Proxy.getInvocationHandler(annotation); 82 changeAnnotationValue(handler, " "); 83 } 84 } 85 // @ExcelEntity注解 86 } else if (field.isAnnotationPresent(ExcelEntity.class)) { 87 Class entityClazz = field.getType(); 88 dynamicChangeAndSaveSourceAnnotation(headers, entityClazz, excelMap); 89 } 90 } 91 return excelMap; 92 } 93 94 // 改變注解屬性值,抽取的公共方法 95 96 private static void changeAnnotationValue(InvocationHandler handler, String propertyValue) { 97 try { 98 Field field = handler.getClass().getDeclaredField("memberValues"); 99 field.setAccessible(true); 100 Map<String, Object> memberValues = (Map<String, Object>) field.get(handler); 101 memberValues.put("name", propertyValue); 102 } catch (Exception e) { 103 log.error("替換注解屬性值出錯!", e); 104 } 105 } 106 107 108 /** 109 * * 遞歸恢復@Excel原始的name屬性 110 * 111 */ 112 public static void dynamicResetAnnotation(Class clazz, Map<String, String> excelMap) { 113 if (excelMap.isEmpty()) { 114 return; 115 } 116 Field[] fields = clazz.getDeclaredFields(); 117 try { 118 for (Field field : fields) { 119 if (field.isAnnotationPresent(Excel.class)) { 120 if (excelMap.containsKey(field.getName())) { 121 Excel annotation = field.getAnnotation(Excel.class); 122 InvocationHandler handler = Proxy.getInvocationHandler(annotation); 123 String sourceName = excelMap.get(field.getName()); 124 changeAnnotationValue(handler, sourceName); 125 } 126 } else if (field.isAnnotationPresent(ExcelCollection.class) && field.getType().isAssignableFrom(List.class)) { 127 // ExcelCollection修改過,才進行復原 128 if (excelMap.containsKey(field.getName())) { 129 ExcelCollection annotation = field.getAnnotation(ExcelCollection.class); 130 InvocationHandler handler = Proxy.getInvocationHandler(annotation); 131 String sourceName = excelMap.get(field.getName()); 132 changeAnnotationValue(handler, sourceName); 133 // ExcelCollection未修改過,遞歸復原泛型字段 134 } else { 135 Type type = field.getGenericType(); 136 if (type instanceof ParameterizedType) { 137 ParameterizedType pt = (ParameterizedType) type; 138 Class collectionClazz = (Class) pt.getActualTypeArguments()[0]; 139 dynamicResetAnnotation(collectionClazz, excelMap); 140 } 141 } 142 } else if (field.isAnnotationPresent(ExcelEntity.class)) { 143 Class entityClazz = field.getType(); 144 dynamicResetAnnotation(entityClazz, excelMap); 145 } 146 } 147 } catch (Exception e) { 148 log.error("解析動態表頭,恢復注解屬性值出錯!", e); 149 } 150 } 151 152 153 }
編寫easypoi導出的工具類
EasyPoiExcelUtil
package com.shiwen.jdzx.server.util; import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; /** * @author wangjie * @date 2019/12/23 18:24 * @description * @company 石文軟件有限公司 */ public class EasyPoiExcelUtil { public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, boolean isCreateHeader, HttpServletResponse response) { ExportParams exportParams = new ExportParams(title, sheetName); exportParams.setCreateHeadRows(isCreateHeader); defaultExport(list, pojoClass, fileName, response, exportParams); } public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) { defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName)); } public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) { defaultExport(list, fileName, response); } private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) { Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list); if (workbook != null) ; downLoadExcel(fileName, response, workbook); } private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) { try { response.setHeader("content-Type", "application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); response.setCharacterEncoding("UTF-8"); workbook.write(response.getOutputStream()); } catch (IOException e) { //throw new NormalException(e.getMessage()); } } private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) { Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF); if (workbook != null) ; downLoadExcel(fileName, response, workbook); } public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) { if (StringUtils.isBlank(filePath)) { return null; } ImportParams params = new ImportParams(); params.setTitleRows(titleRows); params.setHeadRows(headerRows); List<T> list = null; try { list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params); } catch (NoSuchElementException e) { //throw new NormalException("模板不能為空"); } catch (Exception e) { e.printStackTrace(); //throw new NormalException(e.getMessage()); } return list; } public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) { if (file == null) { return null; } ImportParams params = new ImportParams(); params.setTitleRows(titleRows); params.setHeadRows(headerRows); List<T> list = null; try { list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params); } catch (NoSuchElementException e) { // throw new NormalException("excel文件不能為空"); } catch (Exception e) { //throw new NormalException(e.getMessage()); System.out.println(e.getMessage()); } return list; } }
編寫控制層
DataReportExcelController
List<String> exportField參數是表頭信息jh,jb......
package com.shiwen.jdzx.server.controller; import com.shiwen.jdzx.common.WellCondition; import com.shiwen.jdzx.model.daily.DrillingDaily; import com.shiwen.jdzx.server.dao.mapper.DrillingDailyDao; import com.shiwen.jdzx.server.service.DataReportExcelService; import com.shiwen.jdzx.server.util.ExportExcelUtil; import com.shiwen.jdzx.server.util.ModifyAnnotationValues; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List; /** * @author wangjie * @date 2019/12/21 11:39 * @description 資料處理導出excel * @company 石文軟件有限公司 */ @RestController @RequestMapping("/report") public class DataReportExcelController { @Autowired private DataReportExcelService dataReportExcelService; /** * 根據傳入的表頭信息靈活導出 * * @param response */ @RequestMapping("/excel/{type}") public void excel(HttpServletResponse response,@PathVariable("type") String type, String startDate, String endDate, String completed, String oilField, String firstName, String wellType,String jh,@RequestParam("exportField") List<String> exportField) throws Exception { WellCondition condition = new WellCondition(); condition.setStartDate(startDate); condition.setEndDate(endDate); condition.setOilField(oilField); condition.setFirstName(firstName); condition.setWellType(wellType); condition.setJh(jh); condition.setCompleted(completed); condition.setExport(exportField); dataReportExcelService.excel(response,condition,type); } }
編寫導出的server層
WellCondition condition 封裝的是條件參數
String type 導出可能是有多次導出,這個是傳入的路徑 比如首頁需要導出 /index 就接受index就行
package com.shiwen.jdzx.server.service; import com.shiwen.jdzx.common.WellCondition; import org.springframework.ui.ModelMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author wangjie * @date 2019/12/21 11:45 * @description * @company 石文軟件有限公司 */ public interface DataReportExcelService { void excel(HttpServletResponse response,WellCondition condition,String type) throws Exception; }
編寫導出的server層 的實現類
package com.shiwen.jdzx.server.service.impl; import com.shiwen.jdzx.common.WellCondition; import com.shiwen.jdzx.model.OverviewDaily; import com.shiwen.jdzx.model.daily.DrillingDaily; import com.shiwen.jdzx.server.dao.mapper.DrillingDailyDao; import com.shiwen.jdzx.server.dao.mapper.WellDao; import com.shiwen.jdzx.server.service.DataReportExcelService; import com.shiwen.jdzx.server.util.Constant; import com.shiwen.jdzx.server.util.EasyPoiExcelUtil; import com.shiwen.jdzx.server.util.ModifyAnnotationValues; import com.shiwen.publics.pager.PagerOracleImpl; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author wangjie * @date 2019/12/21 11:50 * @description * @company 石文軟件有限公司 */ @Slf4j @Service public class DataReportExcelServiceImpl implements DataReportExcelService { @Autowired private DrillingDailyDao dailyDao; @Autowired private WellDao wellDao; @Override public void excel(HttpServletResponse response, WellCondition condition,String type) throws Exception { Map<String, String> excelMap=new HashMap<>(); Map<String, String> stringStringMap =null; PagerOracleImpl pager=new PagerOracleImpl(); pager.setCurPage(0); switch (type){ case Constant.DRILLING_DAILY: //修改注解 @Excel中的name值, stringStringMap=ModifyAnnotationValues.dynamicChangeAndSaveSourceAnnotation(condition.getExport(), DrillingDaily.class, excelMap); List<DrillingDaily> allDrillingDaily = dailyDao.getDrillingDaily(condition,pager); //導出excel EasyPoiExcelUtil.exportExcel(allDrillingDaily, Constant.mapList.get(type), Constant.mapList.get(type), DrillingDaily.class, Constant.mapList.get(type)+Constant.suffix, response); //導出完成恢復注解的原始值 ModifyAnnotationValues.dynamicResetAnnotation( DrillingDaily.class,stringStringMap); break; case Constant.OVERVIEW_DAILY: stringStringMap=ModifyAnnotationValues.dynamicChangeAndSaveSourceAnnotation(condition.getExport(), OverviewDaily.class, excelMap); List<OverviewDaily> overviewDailies = wellDao.listOverviewDailyAll(condition); EasyPoiExcelUtil.exportExcel(overviewDailies, Constant.mapList.get(type), Constant.mapList.get(type), OverviewDaily.class, Constant.mapList.get(type)+Constant.suffix, response); ModifyAnnotationValues.dynamicResetAnnotation(OverviewDaily.class,stringStringMap); break; case Constant.SINGLE_DRILLING_DAILY: stringStringMap=ModifyAnnotationValues.dynamicChangeAndSaveSourceAnnotation(condition.getExport(), DrillingDaily.class, excelMap); List<DrillingDaily> singleDrillingDaily = dailyDao.getDrillingDailyAll(condition,pager); EasyPoiExcelUtil.exportExcel(singleDrillingDaily, Constant.mapList.get(type), Constant.mapList.get(type), DrillingDaily.class, Constant.mapList.get(type)+Constant.suffix, response); ModifyAnnotationValues.dynamicResetAnnotation(DrillingDaily.class,stringStringMap); default: break; } } }
前段請求
1 /** 2 * 導出 3 */ 4 $scope.exportTable = function () { 5 var param = packParam(); 6 $scope.selTitleField = []; 7 $scope.selTitleName = []; 8 angular.forEach($scope.gridOption, function (item, index) { 9 if (item.checked) { 10 $scope.selTitleField.push(item.field); 11 } 12 }); 13 param.exportField = $scope.selTitleField; 14 param.jh = $scope.filter.jh; 15 var paramArr = []; 16 for (let key in param) { 17 if (param[key] || param[key] === 0) { 18 paramArr.push(key + '=' + param[key]) 19 } 20 } 21 $window.open(url.excel + '?' + paramArr.join('&')); 22 }
dao層我就不寫了。以上代碼根據自己的需要再改下就可以完成,根據傳入的表頭信息靈活導出excel,注意前段傳入的表頭信息,必須和實體的屬性一直