接到一个需求,要求可以自定义导出字段,翻看了大量资料,最终集齐众家所长做了出来,也对excel导出有了不少了解
{{ct.label}}
导出已选择的列
导出全部列
导出
exportDatChecked(){
let columnTitleNew=[]
this.columnTitle.filter(item =>item.checked).forEach(item => {
columnTitleNew.push(item)
})
console.log(columnTitleNew)
this.queryParams.fieldsName= JSON.stringify(columnTitleNew)
console.log(this.queryParams.fieldsName)
this.download('/smms/server-smms/ResourceReserve/exportResearchTasks', {
...this.queryParams
}, `研培任务详情导出${new Date().getTime()}.xls`).then(res => {
if(res.code == '200'){
this.$message.success('导出成功')
}else {
this.$message.error("导出失败")
}
this.queryParams.fieldsName=null
})
this.queryParams.fieldsName=null
},
exportDataAll(){
let columnTitleNew=[]
this.columnTitle.forEach(item => {
columnTitleNew.push(item)
})
this.queryParams.fieldsName= JSON.stringify(columnTitleNew)
console.log(this.queryParams.fieldsName)
this.download('/smms/server-smms/ResourceReserve/exportResearchTasks', {
...this.queryParams
}, `研培任务详情导出${new Date().getTime()}.xls`).then(res => {
if(res.code == '200'){
this.$message.success('导出成功')
}else {
this.$message.error("导出失败")
}
this.queryParams.fieldsName=null
})
this.queryParams.fieldsName=null
},
columnTitle:[
{'label':'任务名称','checked':false,'prop':'name'},
{'label':'任务内容','checked':false,'prop':'taskContent'},
{'label':'责任部门','checked':false,'prop':'dutyDept'},
{'label':'负责人','checked':false,'prop':'responsiblePerson'},
{'label':'上周工作完成情况','checked':false,'prop':'nextWeek'},
{'label':'本周工作计划','checked':false,'prop':'thisWeek'},
{'label':'目标值','checked':false,'prop':'planSchedule'},
{'label':'时序进度','checked':false,'prop':'timingSchedule'},
{'label':'偏差','checked':false,'prop':'deviation'},
{'label':'偏差说明','checked':false,'prop':'remark'},
{'label':'周','checked':false,'prop':'week'},
{'label':'更新时间','checked':false,'prop':'updateTime'},
],
这里我用了element-UI的弹出层,主要是想尝试一下不同的写法,个人觉得应该还可以用dialog写,然后就是这里标题总数是写死了的,不利于后期维护,有想法的可以通过别的方法得到值,不用将它写死。
导出工具类
package com.hckj.utils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class ExportExcel {
// 导出表的标题
private String title;
// 导出表的列名
private String[] rowName;
// 导出表的数据
private List
转换工具类
package com.hckj.utils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Json转换类
*/
public class JsonUtil {
// 使用jackson进行json转换
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static JavaType getCollectionType(Class> collectionClass, Class>... elementClasses) {
return OBJECT_MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses);
}
// 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* 将对象转换成json字符串。
*/
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 将json结果集转化为对象
*
* @param jsonData json数据
* @param beanType 对象中的object类型
*/
public static T jsonToPojo(String jsonData, Class beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将json数据转换成pojo对象list
*/
public static List jsonToList(String jsonData, Class beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String listToJson(List list) throws JsonParseException, JsonMappingException, IOException{
String comment_json = OBJECT_MAPPER.writeValueAsString(list);
return comment_json;
}
public static String mapToJson(Map map) throws JsonParseException, JsonMappingException, IOException{
String comment_json = OBJECT_MAPPER.writeValueAsString(map);
return comment_json;
}
public static Map jsonStringToMap(String jsonString) throws Exception{
Map map = OBJECT_MAPPER.readValue(jsonString, Map.class);
return map;
}
public static String listToJson1(List
Controller层
@ApiOperation("导出研培任务")
@PostMapping("/exportResearchTasks")
public AjaxResult exportResearchTasks(HttpServletResponse response , ResearchTaskDTO researchTasks) throws Exception {
List list = resourceReserveService.queryResearchTasks(researchTasks);
String fileName = DateUtils.getNowDate() +"研培任务详情导出.xls";
String headStr = "attachment; filename=" + fileName;
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition", headStr);
response.setCharacterEncoding("utf-8");
// 把需要展示的列json数据转为List
List> ts = JsonUtil.jsonStringToList1(researchTasks.getFieldsName());
resourceReserveService.exportExcel(response.getOutputStream(),ts,list);
return AjaxResult.success();
重点来了
@Override
public List queryResearchTasks(ResearchTaskDTO researchTasks) {
/*String userName=SecurityUtils.getCurrentUser().getNickName();
if(!userName.contains("管理员") && !userName.contains("运维") ){
researchTasks.setResponsiblePerson(userName);
}
if(userName.contains("江银")){
researchTasks.setResponsiblePerson(null);
}*/
List tasks= resourceReserveMapper.queryResearchTasks(researchTasks);
ArrayList temporaryList = new ArrayList<>();
//排序,使相同名字的数据在相邻的地方
List collect = tasks.stream().map(ResearchTasks::getName).distinct().collect(Collectors.toList());
for (int i = 0; i < collect.size(); i++) {
for (int j = 0; j > cols, List list) throws Exception {
List dataList = new ArrayList();
// 设置Excel列标题
String[] rowsName = new String[cols.size()+1];
rowsName[0] = "序号";
for (int i = 0; i < cols.size(); i++) {
rowsName[i+1] = cols.get(i).get("label").toString();
}
try {
// 设置Excel行数据
for (ResearchTaskDTO p : list) {
Object[] objs = new Object[cols.size()+1];
objs[0] = "";
for (int j = 0; j < cols.size(); j++) {
String prop = cols.get(j).get("prop").toString();
if (prop.equals("name")) {
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name;
}else if (prop.equals("taskContent")){
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name;
}else if (prop.equals("dutyDept")){
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name;
}else if (prop.equals("responsiblePerson")){
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name;
}else if (prop.equals("nextWeek")){
if(p.getNextWeek() != null){
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name;
}else {
objs[j+1] ="/";
}
}else if (prop.equals("thisWeek")){
if(p.getThisWeek() != null){
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name;
}else {
objs[j+1] ="/";
}
}else if (prop.equals("planSchedule")){
p.setPlanSchedule(p.getPlanSchedule()*100);
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name.substring(0, name.lastIndexOf("."))+"%";
}else if (prop.equals("timingSchedule")){
p.setTimingSchedule(p.getTimingSchedule()*100);
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name.substring(0, name.lastIndexOf("."))+"%";
}else if (prop.equals("deviation")){
p.setDeviation(p.getDeviation()*100);
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name.substring(0, name.lastIndexOf("."))+"%";
}else if (prop.equals("remark")){
if(p.getRemark() != null){
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name;
}else {
objs[j+1] ="/";
}
}else if (prop.equals("week")){
if(p.getWeek() != null){
String name = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
objs[j+1] = name;
}else {
objs[j+1] ="/";
}
}else if (prop.equals("updateTime")){
if(p.getUpdateTime() != null){
String dateStr = invokeGetMethod(ResearchTaskDTO.class, prop, p).toString();
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
Date date = new Date();
try{
date = sdf.parse(dateStr);
}catch (Exception e){
e.printStackTrace();
}
String formatStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
objs[j+1] = formatStr;
}else {
objs[j+1] ="/";
}
}
}
dataList.add(objs);
}
}catch (Exception e) {
e.printStackTrace();
}
String title ="2022年国网福建党校(管培中心)研究培训工作周进度看板";
if(list.get(0).getWeek() != null){
title+="("+list.get(0).getWeek()+")";
}
System.out.println(title);
ExportExcel ex = new ExportExcel(title, rowsName, dataList);
try {
ex.export(out);
} catch (Exception e) {
e.printStackTrace();
}
out.flush();
out.close();
}
/**
* 拼接属性,调用目标Class的get方法
*
* @param c 属性所属实体类
* @param filedName 需要调用的属性名
* @param obj 实体类实例
* @return 返回get方法结果
*/
public static Object invokeGetMethod(Class> c, String filedName, Object obj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
String methodName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
Class>[] nullClasses = null;
Method method = c.getMethod(methodName, nullClasses);
Object[] nullObjects = null;
return method.invoke(obj, nullObjects);
}
然后这个是我根据网上的葫芦画瓢来的
后面根据那个导出工具类自己写了个excel
这个就是前端的表格,导出表格也要一样
然后我们来分析一下
public void exportExcel(ServletOutputStream outputStream, List> tableColumns, List> tableData) {
// 设置Excel列标题
String[] rowsName = new String[tableColumns.size()+3];
String[] rowsName1 = new String[tableColumns.size()+3];
rowsName[0] = "序号";
rowsName[1] = "办学校区";
rowsName[2] = "培训班名称";
rowsName1[0] = "序号";
rowsName1[1] = "办学校区";
rowsName1[2] = "培训班名称";
for (int i = 0; i < tableColumns.size(); i++) {
rowsName[i+3] = tableColumns.get(i).get("label1").toString();
rowsName1[i+3] = tableColumns.get(i).get("label2").toString();
}
try {
//新建工作簿
XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
//新建工作表
XSSFSheet sheet = xssfWorkbook.createSheet("住宿统计表");
//指定合并开始行、合并结束行 合并开始列、合并结束列
CellRangeAddress rangeAddress = new CellRangeAddress(0, 1, 0, 0);
//添加要合并地址到表格
sheet.addMergedRegion(rangeAddress);
sheet.addMergedRegion(new CellRangeAddress(tableData.size()+1, tableData.size()+1, 1, 2));
sheet.addMergedRegion(new CellRangeAddress(0, 1, 1, 1));
sheet.addMergedRegion(new CellRangeAddress(0, 1, 2, 2));
//这个合并地址可以多次添加,这里合并的行列也是之前分析的
//创建行,指定起始行号,从0开始
XSSFRow row = sheet.createRow(0);
//创建单元格,指定起始列号,从0开始
XSSFCell cell = row.createCell(0);
// 定義所需要的列數
int columnNum = rowsName.length;
XSSFRow rowRowName = sheet.createRow(1);
for (int i = 0; i < 2; i++) {
if(i==0){
// 將列頭設置到SHEET的單元格中
for (int n = 0; n < columnNum; n++) {
XSSFCell cellRowName = row.createCell(n);
cellRowName.setCellType(CellType.STRING);
XSSFRichTextString text = new XSSFRichTextString(rowsName[n]);
cellRowName.setCellValue(text);
}
}else {
for (int n = 0; n < columnNum; n++) {
XSSFCell cellRowName = rowRowName.createCell(n);
cellRowName.setCellType(CellType.STRING);
XSSFRichTextString text = new XSSFRichTextString(rowsName1[n]);
cellRowName.setCellValue(text);
}
}
}
//这里就是前面2行标题设置,此时已经将1,2行写到工作簿中去了
// 將數據設置到SHEET的單元格中
for (int i = 0; i < tableData.size(); i++) {
XSSFRow rows= sheet.createRow(i + 2);
List data = (List) tableData.get(i).get("data");
String trainClassName = (String) tableData.get(i).get("trainClassName");
String campusType=null;
String type=null;
if(i != tableData.size()-1){
campusType = (String) tableData.get(i).get("campusType");
type= remoteDictService.selectDictLabel("campus_type", campusType).getMsg();
}
for (int j = 0; j < data.size()+3; j++) {
XSSFCell xssfCell=null;
if(j==0) {
xssfCell = rows.createCell(j, CellType.NUMERIC);
xssfCell.setCellValue(i + 1);
}else if(j==1) {
xssfCell = rows.createCell(j, CellType.STRING);
if (campusType != null) {
xssfCell.setCellValue(type);
}else {
xssfCell.setCellValue(trainClassName);
}
}else if(j==2) {
xssfCell = rows.createCell(j, CellType.STRING);
xssfCell.setCellValue(trainClassName);
}else {
xssfCell = rows.createCell(j, CellType.STRING);
if (!"".equals(data.get(j-3)) && data.get(j-3) != null) {
xssfCell.setCellValue(data.get(j-3).toString());
} else {
xssfCell.setCellValue(" ");
}
}
}
}
//这一层循环是将数据写到工作簿中去,这里这样写的原因是基于数据而改变的
if (xssfWorkbook != null) {
try {
xssfWorkbook.write(outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
}catch (Exception e) {
e.printStackTrace();
}
}
这里就自己实现了,我还没有用到那个样式,有需要的同学也可以用一下导出工具类中的样式渲染
参加工作之后,导入导出经常用到,之前一直用的开源软件提供的,也有大神自己根据业务写的导出工具类,这还是第一次自己理解excel怎么写的,意义重大,也将这个分享给大家,虽然这个不能复用,哈哈