第一步添加依赖
<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,注意前段传入的表头信息,必须和实体的属性一直
小蘑菇