最近需要写一个功能,是前段调用后端导出excel功能,小爷我亲自写了一套,特此让大家可以减少走坑。
废话不多说,直接上代码。
导出功能是最常用的,下面的代码中用到了反射的思想,比如,你查询出来的List<T>结果集,只想导出指定的那些字段数据,就非常方便了,代码如下:
基本思路为:创建一个表格对象,将数据set到表格中,将表格流写入response返回
准备工作:pom中加入以下依赖:
<!--导出功能jar-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15-beta2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15-beta2</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
创建工具类
package com.tian.tools.utils.file;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.commons.collections.CollectionUtils;
import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Date;
/**
* @Description 导出表格工具类
* 基本思路:创建表格对象--->将数据set进表格--->将表格流写入response返回
* @author 吴昊天
* @date 2020/5/15 11:06
*/
public class FilePortUtil {
/**
* 方法描述:导出功能
* 注意:泛型T类字段名和containBean集合里字段名字的一致性
* @author Harry
* @date 2020/5/15 11:13
* @param response
* @param title 表名
* @param headers 表头
* @param list 数据集
* @param containBean 数据集类型字段
* @param <T>
* @throws Exception
* @return
**/
public static <T> void exportExcel(HttpServletResponse response, String title, String[] headers, List<T> list, List<String> containBean) throws Exception{
HSSFWorkbook workbook = null;
try {
workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet(title);
HSSFRow row = sheet.createRow(0);
//创建第一行表头
for (short i = 0; i < headers.length; i++){
HSSFCell cell = row.createCell(i);
HSSFRichTextString textString = new HSSFRichTextString(headers[i]);
cell.setCellValue(textString);
}
Iterator<T> it = list.iterator();
int index = 0;
while (it.hasNext()){
index++;
row = sheet.createRow(index);
T t = (T)it.next();
//通过反射得到字段
Field[] fields = t.getClass().getDeclaredFields();
//如果需要匹配
if (CollectionUtils.isEmpty(containBean)){
for (int j = 0; j < containBean.size(); j++){
for (int i = 0; i < fields.length; i++){
Field field = fields[i];
if (!field.getName().equals(containBean.get(j)))
continue;
setCellValue(t,field,row,j);
}
}
} else {
for (int i = 0; i < fields.length; i++){
Field field = fields[i];
setCellValue(t,field,row,i);
}
}
}
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + new String((title).getBytes(), "ISO8859-1") + ".xls");
workbook.write(response.getOutputStream());
}finally {
if (workbook != null){
workbook.close();
}
}
}
/**
* 方法描述:设置每一行中的列
* @author Harry
* @date 2020/5/15 11:44
* @param t
* @param field
* @param row
* @param index
* @return T
**/
private static <T> void setCellValue(T t, Field field, HSSFRow row, int index) {
HSSFCell cell = row.createCell(index);
Object value = invoke(t, field);
String textValue = null;
if (value != null){
if (value instanceof Date){
Date date = (Date) value;
textValue = DateFormatUtils.format(date,"yyyy-MM-dd HH:mm:ss");
} else {
textValue = value.toString();
}
}
if (textValue != null){
cell.setCellValue(textValue);
}
}
/**
* 方法描述:通过反射获取数据集字段
* @author Harry
* @date 2020/5/15 11:42
* @param t 泛型
* @param field
* @return T
**/
private static <T> Object invoke(T t, Field field){
try{
String fieldName = field.getName();
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fieldName,t.getClass());
Method readMethod = propertyDescriptor.getReadMethod();
return readMethod.invoke(t);
}catch (Exception e){
return null;
}
}
}
控制层写方法
/**
* 方法描述:导出EXCEL表格
* @author Harry
* @date 2020/5/15 11:56
* @param
* @return
**/
@ResponseBody
@GetMapping("exportExcel")
public void exportExcel(HttpServletResponse response){
//导出的表格名称
String title = "项目工资列表";
//表中第一行表头字段
String [] headers ={"月份","登记时间","项目名称","工作量","应发工资(元)","实发工资(元)","月结余(元)","备注"};
//从数据库查询出来的结果集
List<PProjectSalary> pProjectSalaryList = projectSalaryService.findAll();
//具体需要写入excel需要的那些字段,这些字段从PprojectSalary类中拿,也就是上面的实际数据结果集的泛型
List<String> list = Arrays.asList("id","months","checkInTime","project","workload","payable","actualSalary","monthLaybalance","remarks");
try {
FilePortUtil.exportExcel(response,title,headers,pProjectSalaryList,list);
}catch (Exception e){
if (logger.isErrorEnabled()){
logger.error(e.getMessage());
error(e.getMessage());
}
}
}
前段写一个点击事件
<button type="button" class="btn btn-success" onclick="exportOut()">导出</button>
js方法
//导出 按钮
function exportOut() {
window.location.href='<%=basePath%>/projectSalary/exportExcel'
}
这是下载到本地的excel
扫描二维码关注公众号,回复:
11199283 查看本文章
打开之后的样子!
亲测ok,如有疑问,请留言哈!