最近在做公司管理系统的Excel导出功能,使用的是Poi。查阅了许多网上的代码,基本上都不是很全面,代码跑不起来。在不停的试错之后终于实现了,下面贴上代码和相关注释。
SpringBoot、jdk15(版本不影响)、vue3.0
在pom.xml中添加poi的依赖:
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.14</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.14</version>
</dependency>
代码如下(示例):
exportExcel:function(){
this.$http({
//发送ajax获得后台查询的数据往表里添
url: this.$http.adornUrl('/student/student/export'),
method: 'post',
responseType: 'blob',//必须加该属性,设置响应头的格式
data: this.$http.adornData({
//里面为我传的条件查询参数,可无视
'classId':this.exportExcelParams.classId,
'school':this.exportExcelParams.school,
'createTime':this.exportExcelParams.createTime,
'checkBox':this.exportExcelParams.checkInfoOptions
})
}).then(function(response) {
if(response &&response.data!=null){
//将后台获得的数据传给blob对象
let blob = new Blob([response.data], {
type: "application/vnd.ms-excel;charset=utf-8",
});
//创建dom元素
let downloadElement = document.createElement('a');
let href = window.URL.createObjectURL(blob); //创建下载的链接
downloadElement.href = href;
//设置文件名
const date = new Date()
downloadElement.download = '学生信息表'+date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()+'.xls'; //下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); //点击下载
document.body.removeChild(downloadElement); //下载完成移除元素
window.URL.revokeObjectURL(href); //释放掉blob对象
}else{
this.$message.error('导出失败')
}
})
}
DAO层:
@Mapper
public interface StudentDao extends BaseMapper<StudentEntity> {
//根据查询条件导出excel文件
List<ExportStudentExcel> searchStuListForExcel(HashMap map);
}
mapper:
<select id="searchStuListForExcel" resultType="cn.tentact.modules.student.form.ExportStudentExcel" parameterType="Hashmap">
SELECT
st.id,
st.name,
st.sex,
st.birthday,
st.politics,
st.pid,
st.school,
st.major,
st.education,
st.g_time,
st.g_status,
st.home_address,
st.current_address,
st.tel,
st.wechat,
st.email,
st.intent_place,
st.intent_job,
st.parent_name,
st.parent_tel,
stt.type,
c.class_name,
st.s_status,
st.remark,
st.user_id,
st.create_time
FROM
tb_student st
LEFT JOIN tb_class c
ON st.class_id=c.id
LEFT JOIN tb_student_type stt
ON st.type_id=stt.id
WHERE 1=1
<if test="school!=null and sex!=''">
AND st.school like CONCAT('%',#{school},'%')
</if>
<if test="classId!=null and classId!=''">
AND st.class_id=#{classId}
</if>
<if test="createTime!=null">
AND st.create_time >=#{createTime} AND st.create_time <= date_add(#{createTime} ,interval 1 day)
</if>
ORDER BY st.id DESC
</select>
实体类:
@Data
@TableName("tb_student")
public class ExportStudentExcel {
/**
* 学生id
*/
@TableId
private Long id;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private String sex;
/**
* 出生日期
*/
private String birthday;
/**
* 政治面貌
*/
private String politics;
/**
* 身份证号
*/
private String pid;
/**
* 学校
*/
private String school;
/**
* 专业
*/
private String major;
/**
* 毕业时间
*/
@TableField("g_time")
private String gTime;
/**
* 学历
*/
private String education;
/**
* 毕业情况
*/
@TableField("g_status")
private String gStatus;
/**
* 家庭住址
*/
private String homeAddress;
/**
* 当前住址
*/
private String currentAddress;
/**
* 电话
*/
private String tel;
/**
* 微信号
*/
private String wechat;
/**
* 邮箱
*/
private String email;
/**
* 意向就业地
*/
private String intentPlace;
/**
* 意向岗位
*/
private String intentJob;
/**
* 父母姓名
*/
private String parentName;
/**
* 父母电话
*/
private String parentTel;
/**
* 关联学生来源表ID
*/
private String type;
/**
* 隶属班级ID
*/
private String className;
/**
* 学习状态
*/
@TableField("s_status")
private String sStatus;
/**
* 备注
*/
private String remark;
/**
* 用户id
*/
private Long userId;
/**
* 填表日期
*/
private Date createTime;
}
Export工具类(直接复制粘贴是可用的):
package cn.tentact.common.utils;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
public class ExportExcelUtils {
/**
* 导出Excel
*
* @param excelName 要导出的excel名称
* @param list 要导出的数据集合
* @param fieldMap 中英文字段对应Map,即要导出的excel表头
* @param response 使用response可以导出到浏览器
* @param
*/
public static <T> void export(String excelName, List<T> list, LinkedHashMap<String, String> fieldMap, HttpServletResponse response) {
try {
response.setHeader("Content-Disposition", "attachment;filename="+excelName);
} catch (Exception e1) {
e1.printStackTrace();
}
try {
//创建一个WorkBook,对应一个Excel文件
HSSFWorkbook wb = new HSSFWorkbook();
//在Workbook中,创建一个sheet,对应Excel中的工作薄(sheet)
HSSFSheet sheet = wb.createSheet(excelName);
//创建单元格,并设置值表头 设置表头居中
HSSFCellStyle style = wb.createCellStyle();
//创建一个居中格式
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
style.setAlignment(XSSFCellStyle.ALIGN_CENTER);
//设置边框线
style.setBorderBottom(XSSFCellStyle.BORDER_THIN);
style.setBorderLeft(XSSFCellStyle.BORDER_THIN);
style.setBorderTop(XSSFCellStyle.BORDER_THIN);
style.setBorderRight(XSSFCellStyle.BORDER_THIN);
// 填充工作表
fillSheet(sheet, list, fieldMap, style);
//渲染第一行背景色为灰色,并设置列宽为10个字节
for (int i = 0; i <= sheet.getLastRowNum(); i++) {
HSSFRow row1 = sheet.getRow(i);
for (int j = 0; j < row1.getLastCellNum(); j++) {
HSSFCell cell1 = row1.getCell(j);
row1.setHeightInPoints(24);
cell1.setCellStyle(style);
sheet.setColumnWidth((short)j,10*256);
}
}
//渲染第一行的背景色为灰色
HSSFRow row = sheet.getRow(0);
HSSFCellStyle style1 = wb.createCellStyle();
style1.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
style1.setFillPattern(CellStyle.SOLID_FOREGROUND);
style1.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
style1.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//设置边框线
style1.setBorderBottom(XSSFCellStyle.BORDER_THIN);
style1.setBorderLeft(XSSFCellStyle.BORDER_THIN);
style1.setBorderTop(XSSFCellStyle.BORDER_THIN);
style1.setBorderRight(XSSFCellStyle.BORDER_THIN);
for (int i = 0; i < row.getLastCellNum() ; i++) {
HSSFCell cell = row.getCell(i);
cell.setCellStyle(style1);
}
//将文件输出
OutputStream ouputStream = response.getOutputStream();
wb.write(ouputStream);
ouputStream.flush();
ouputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean chooseIntoField(List<String> list,String name){
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals("name")){
return true;
}
}
return false;
}
/**
* 根据字段名获取字段对象
*
* @param fieldName 字段名
* @param clazz 包含该字段的类
* @return 字段
*/
public static Field getFieldByName(String fieldName, Class<?> clazz) {
// 拿到本类的所有字段
Field[] selfFields = clazz.getDeclaredFields();
// 如果本类中存在该字段,则返回
for (Field field : selfFields) {
//如果本类中存在该字段,则返回
if (field.getName().equals(fieldName)) {
return field;
}
}
// 否则,查看父类中是否存在此字段,如果有则返回
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null && superClazz != Object.class) {
//递归
return getFieldByName(fieldName, superClazz);
}
// 如果本类和父类都没有,则返回空
return null;
}
/**
* 根据字段名获取字段值
*
* @param fieldName 字段名
* @param o 对象
* @return 字段值
* @throws Exception 异常
*/
public static Object getFieldValueByName(String fieldName, Object o)
throws Exception {
Object value = null;
//根据字段名得到字段对象
Field field = getFieldByName(fieldName, o.getClass());
//如果该字段存在,则取出该字段的值
if (field != null) {
field.setAccessible(true);//类中的成员变量为private,在类外边使用属性值,故必须进行此操作
value = field.get(o);//获取当前对象中当前Field的value
} else {
throw new Exception(o.getClass().getSimpleName() + "类不存在字段名 "
+ fieldName);
}
return value;
}
/**
* 根据带路径或不带路径的属性名获取属性值,即接受简单属性名,
* 如userName等,又接受带路径的属性名,如student.department.name等
*
* @param fieldNameSequence 带路径的属性名或简单属性名
* @param o 对象
* @return 属性值
* @throws Exception 异常
*/
public static Object getFieldValueByNameSequence(String fieldNameSequence,
Object o) throws Exception {
Object value = null;
// 将fieldNameSequence进行拆分
String[] attributes = fieldNameSequence.split("\\.");
if (attributes.length == 1) {
value = getFieldValueByName(fieldNameSequence, o);
} else {
// 根据数组中第一个连接属性名获取连接属性对象,如student.department.name
Object fieldObj = getFieldValueByName(attributes[0], o);
//截取除第一个属性名之后的路径
String subFieldNameSequence = fieldNameSequence
.substring(fieldNameSequence.indexOf(".") + 1);
//递归得到最终的属性对象的值
value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj);
}
return value;
}
/**
* 向工作表中填充数据
*
* @param sheet excel的工作表名称
* @param list 数据源
* @param fieldMap 中英文字段对应关系的Map
* @param style 表格中的格式
* @throws Exception 异常
*/
public static <T> void fillSheet(HSSFSheet sheet, List<T> list,
LinkedHashMap<String, String> fieldMap, HSSFCellStyle style) throws Exception {
// 定义存放英文字段名和中文字段名的数组
String[] enFields = new String[fieldMap.size()];
String[] cnFields = new String[fieldMap.size()];
// 填充数组
int count = 0;
for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
enFields[count] = entry.getKey();
cnFields[count] = entry.getValue();
count++;
}
//在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short
HSSFRow row = sheet.createRow((int) 0);
// 填充表头
for (int i = 0; i < cnFields.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellValue(cnFields[i]);
cell.setCellStyle(style);
sheet.autoSizeColumn(i);
}
// 填充内容
for (int index = 0; index < list.size(); index++) {
row = sheet.createRow(index + 1);
// 获取单个对象
T item = list.get(index);
for (int i = 0; i < enFields.length; i++) {
Object objValue = getFieldValueByNameSequence(enFields[i], item);
String fieldValue = objValue == null ? "" : objValue.toString();
row.createCell(i).setCellValue(fieldValue);
}
}
}
}
serviceImpl层:
@Override
@Transactional
public List<ExportStudentExcel> searchStuListForExcel(HashMap map) {
List<ExportStudentExcel> userList = studentDao.searchStuListForExcel(map);
return userList;
}
controller层(其中的for循环为判断条件,可无视,直接使用fieldMap.put(“与实体类对应的字段名”,“显示在excel中的表头字段”)即可):
/**
* 导出excel文件
*/
@RequestMapping(value = "/export")
public List<ExportStudentExcel> exportExcel(@RequestBody Map<String,Object> params, HttpServletResponse response){
List<ExportStudentExcel> userList = studentService.searchStuListForExcel((HashMap) params);
List<HashMap> checkBox = (List<HashMap>) params.get("checkBox");
List<String> optionCn=new ArrayList<>();
List<String> optionEn=new ArrayList<>();
for(HashMap option :checkBox){
optionCn.add(option.get("label").toString());
optionEn.add(option.get("value").toString());
}
LinkedHashMap<String,String> fieldMap = new LinkedHashMap<String,String>();
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("id")){
fieldMap.put("id","序号");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("name")){
fieldMap.put("name","姓名");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("sex")){
fieldMap.put("sex","性别");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("birthday")){
fieldMap.put("birthday","出生日期");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("politics")){
fieldMap.put("politics","政治面貌");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("pid")){
fieldMap.put("pid","身份证");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("school")){
fieldMap.put("school","学校");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("major")){
fieldMap.put("major","专业");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("time")){
fieldMap.put("gTime","毕业时间");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("education")){
fieldMap.put("education","学历");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("gStatus")){
fieldMap.put("gStatus","毕业情况");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("homeAddress")){
fieldMap.put("homeAddress","家庭住址");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("currentAddress")){
fieldMap.put("currentAddress","当前住址");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("tel")){
fieldMap.put("tel","电话");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("wechat")){
fieldMap.put("wechat","微信号");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("email")){
fieldMap.put("email","邮箱");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("intentPlace")){
fieldMap.put("intentPlace","意向城市");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("intentJob")){
fieldMap.put("intentJob","意向工作");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("parentName")){
fieldMap.put("parentName","父母姓名");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("parentTel")){
fieldMap.put("parentTel","父母电话");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("type")){
fieldMap.put("type","学生来源");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("className")){
fieldMap.put("className","班级");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("sStatus")){
fieldMap.put("sStatus","学习状态");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("remark")){
fieldMap.put("remark","备注");
break;
}
}
for (int i = 0; i < optionEn.size(); i++) {
if (optionEn.get(i).equals("createTime")){
fieldMap.put("createTime","入学时间");
break;
}
}
String title = "学生信息表";
ExportExcelUtils.export(title,userList,fieldMap,response);
return userList;
}
若有不对的地方烦请指出,如果对你有帮助的话不忘点个赞!