引言
java后台导出表格一般分两种:注解配置(@Excel)导出和自定义导出
注解配置(@Excel)导出
添加poi依赖
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>${easypoi.version}</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>${easypoi.version}</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>${easypoi.version}</version>
</dependency>
建实体类并用@Excel注解
@Data
public class EmployeeXls {
//type=2为导出照片,传入照片的路径
@Excel(name = "照片", type = 2, width = 20, height = 40)
private String photoUrl;
@Excel(name = "员工ID(必填)", width = 20, isImportField = "true_st")
private String personNo;
@Excel(name = "姓名(必填)", width = 15, isImportField = "true_st")
private String employeename;
@Excel(name = "身份证/IC卡号", width = 30)
private String idcard;
@Excel(name = "性别(必填)", width = 15)
private String gender;
@Excel(name = "手机号码", width = 25)
private String phone;
@Excel(name = "邮箱", width = 30)
private String email;
@Excel(name = "生日", width = 15)
private String birthday;
@Excel(name = "入职日期", width = 15)
private String entryDate;
@Excel(name = "所属分组", width = 30)
private String employeeGroupName;
@Excel(name = "是否需要考勤", width = 30)
private String attendanceFlag;
@Excel(name = "考勤班次", width = 20)
private String attendanceName;
}
导出excel模板
Controller端实现类 |
@PostMapping("/tpl")
public ResponseInfo exportTpl(HttpServletResponse response) {
ExportParams exportParams = new ExportParams();
exportParams.setSheetName(MessageResolver.getMessage("xls.employeeTemplate", "员工模板"));
response.setContentType("application/x-download;charset=UTF-8");
response.addHeader("Content-disposition", "filename=employee.xls");
List<EmployeeXls> list = new ArrayList<>();
Workbook workbook = null;
try {
//ExcelUtis chooseLang方法是为了做国际化,为自定义的一个方法
workbook = ExcelExportUtil.exportExcel(exportParams, ExcelUtils.chooseLang(EmployeeXls.class), list);
} catch (Exception e) {
e.printStackTrace();
}
if(null==workbook){
return new ResponseInfo(false);
}
Sheet sheet = workbook.getSheetAt(0);
// 性别下拉选框
CellRangeAddressList genderAddressList = new CellRangeAddressList(0, 100, 3, 3);
final String[] genderList = new String[]{MessageResolver.getMessage("xls.male", "男"), MessageResolver.getMessage("xls.female", "女")};
ExcelUtils.setExcelDropDownBox(genderAddressList, sheet, genderList);
// 是否考勤下拉选框
CellRangeAddressList attendanceAddressList = new CellRangeAddressList(0, 100, 9, 9);
final String[] attendanceFlagList = new String[]{MessageResolver.getMessage("xls.yes", "是"), MessageResolver.getMessage("xls.no", "否")};
ExcelUtils.setExcelDropDownBox(attendanceAddressList, sheet, attendanceFlagList);
//考勤班次下拉框
CellRangeAddressList attendanceAddressRuleList = new CellRangeAddressList(0, 100, 10, 10);
List<AttendanceRule> allRules = attendanceRuleService.findAllRule();
final String[] attendanceRuleList = new String[allRules.size()];
int i = 0;
for (AttendanceRule allRule : allRules) {
attendanceRuleList[i++] = allRule.getName();
}
ExcelUtils.setExcelDropDownBox(attendanceAddressRuleList, sheet, attendanceRuleList);
// 员工分组下拉选框
CellRangeAddressList groupAddressList = new CellRangeAddressList(0, 100, 8, 8);
List<EmployeeGroup> employeeGroups = employeeGroupService.findAll(false);
final String[] GROUP_LIST=new String[employeeGroups.size()];
int i=0;
for(EmployeeGroup employeeGroup:employeeGroups){
GROUP_LIST[i++]=employeeGroup.getName();
}
ExcelTemplateSetUtil.setExcelDropDownBox(groupAddressList,sheet,GROUP_LIST);
// 设置身份证号,生日,入职日期为文本格式
CellStyle cellStyle = workbook.createCellStyle();
DataFormat dataFormat = workbook.createDataFormat();
cellStyle.setDataFormat(dataFormat.getFormat("@"));
sheet.setDefaultColumnStyle(2, cellStyle);
sheet.setDefaultColumnStyle(6, cellStyle);
sheet.setDefaultColumnStyle(7, cellStyle);
OutputStream fos = null;
try {
fos = response.getOutputStream();
workbook.write(fos);
} catch (IOException e) {
e.printStackTrace();
return new ResponseInfo(false);
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
创建ExcelUtis类 |
public final class ExcelUtils {
//设置下拉框
public static void setExcelDropDownBox(CellRangeAddressList addressList, Sheet sheet, String[] dataList) {
DVConstraint dvConstraint = DVConstraint.createExplicitListConstraint(dataList);
HSSFDataValidation dataValidation = new HSSFDataValidation(addressList, dvConstraint);
dataValidation.setSuppressDropDownArrow(false);
dataValidation.createPromptBox(MessageResolver.getMessage("xls.title", "输入提示"), MessageResolver.getMessage("xls.text", "请从下拉列表中"));
dataValidation.setShowPromptBox(true);
sheet.addValidationData(dataValidation);
}
//利用注解对生成表格的标题国际化
public static Class<?> chooseLang(Class<?> pojoClass)
throws NoSuchFieldException, IllegalAccessException {
//获取实体类中所有字段
Field[] fields = pojoClass.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
// 获取字段上的注解
Excel anoExcel = field.getAnnotation(Excel.class);
if (anoExcel != null) {
// 获取代理处理器
InvocationHandler invocationHandler = Proxy.getInvocationHandler(anoExcel);
// 获取私有 memberValues 属性
Field f = invocationHandler.getClass().getDeclaredField("memberValues");
f.setAccessible(true);
// 获取实例的属性map
Map<String, Object> memberValues = (Map<String, Object>) f.get(invocationHandler);
// 获取属性值
String excelValue = (String) memberValues.get("name");
if (StringUtils.isNotBlank(excelValue)) {
//根据传入的语言标识,重新设置属性值
memberValues.put("name", MessageResolver.getMessage("xls." + name));
}
}
}
return pojoClass;
}
}
导入Excel表格
导入Controller类 |
public ResponseInfo importExcel(@RequestParam(value = "file") MultipartFile file, Integer dealWithType, HttpServletRequest request) {
Integer siteId = SystemContextUtils.getSiteId(request);
ImportParams params = new ImportParams();
List<EmployeeXls> list;
try {
//根据需求对Excel导入文件进行校验
boolean flag = ExcelUtils.validExcelTemple(file.getInputStream(), EmployeeXls.class);
if (!flag) {
return new ResponseInfo(OtherErrorCodeEnum.UPLOAD_FILE_ERROR.getCode(), OtherErrorCodeEnum.UPLOAD_FILE_ERROR.getDefaultMessage());
}
list = ExcelImportUtil.importExcel(file.getInputStream(), EmployeeXls.class, params);
} catch (Exception e) {
e.printStackTrace();
return new ResponseInfo(OtherErrorCodeEnum.IMPORT_EXCEL_ERROR.getCode(), OtherErrorCodeEnum.IMPORT_EXCEL_ERROR.getDefaultMessage());
}
// log.debug("import employees: {}", FastJsonUtils.toJson(list));
// 批量保存员工信息
ResponseInfo info;
// 并发处理
final ReentrantLock lock = this.lock;
lock.lock();
try {
info = employeeService.batchSaveEmployees(siteId, list, dealWithType);
} catch (Exception e) {
return new ResponseInfo(OtherErrorCodeEnum.UPLOAD_FILE_ERROR.getCode(), OtherErrorCodeEnum.UPLOAD_FILE_ERROR.getDefaultMessage());
} finally {
lock.unlock();
}
return info;
}
validExcelTemple对Excell文件标题栏进行校验 |
public final class ExcelUtils {
//利用反射检验传入excel模板标题栏
public static boolean validExcelTemple(InputStream inputStream, Class<?> pojoClass)
throws NoSuchFieldException, IllegalAccessException {
Workbook workbook = null;
boolean flag = true;
try {
workbook = new HSSFWorkbook(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
if (null != workbook) {
Sheet sheet = workbook.getSheetAt(0);
Row row = sheet.getRow(0);
Field[] fields = pojoClass.getDeclaredFields();
int length = row.getLastCellNum();
if (length >= fields.length - 2) {
for (int i = 0; i < length; i++) {
String name = fields[i + 2].getName();
String value = row.getCell(i).getStringCellValue();
Excel excel = fields[i + 2].getAnnotation(Excel.class);
if (excel != null) {
InvocationHandler invocationHandler = Proxy.getInvocationHandler(excel);
Field f = invocationHandler.getClass().getDeclaredField("memberValues");
f.setAccessible(true);
Map<String, Object> memberValues = (Map<String, Object>) f.get(invocationHandler);
String fieldValue = (String) memberValues.get("name");
String message = "";
if (StringUtils.isNotBlank(fieldValue)) {
message = MessageResolver.getMessage("xls." + name);
}
if (!message.equals(value)) {
flag = false;
break;
}
}
}
} else {
flag = false;
}
}
return flag;
}
}
自定义Excel表格导出
1 定义一个实体类包含标题栏,需要导出数据,页签名称
2 定义一个Contoller类向前端导出
3 定义一个ExcelUntils类对标题,数据数据,表格格式 进行处理
创建实体类
@Data
public class ExportAnswerXls {
/**
* 标题栏
*/
private List<String> titles;
/**
* 数据
*/
private List<List<Object>> rows;
/**
* 页签名称
*/
private String name;
}
创建Contoller类
public ResponseInfo exportAnswers(@RequestBody ExportAnswerDto exportAnswerDto, HttpServletRequest request, HttpServletResponse response) {
Integer siteId = SystemContextUtils.getSiteId(request);
response.setContentType("application/x-download;charset=UTF-8");
response.addHeader("Content-disposition", "filename=employee.xls");
ExportAnswerXls excelData = answerService.exportAnswerXls(exportAnswerDto,siteId);
XSSFWorkbook wb = new XSSFWorkbook();
try {
String sheetName = excelData.getName();
if (null == sheetName) {
sheetName = "Sheet1";
}
XSSFSheet sheet = wb.createSheet(sheetName);
//在Utils类里面处理数据及格式
ExcelUtils.writeExcel(wb, sheet, excelData);
try {
wb.write(response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
} finally {
try {
wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
创建ExcelUtills类
设置单元格格式以供标题栏和数据单元格添加 |
单元格格式自动扩增
private static void autoSizeColumns(Sheet sheet, int columnNumber) {
for (int i = 0; i < columnNumber; i++) {
//i=1为照片列需设置固定宽高
if (i == 1) {
sheet.setColumnWidth(i, 2000);
continue;
}
int orgWidth = sheet.getColumnWidth(i);
sheet.autoSizeColumn(i, true);
int newWidth = (int) (sheet.getColumnWidth(i) + 100);
if (newWidth > orgWidth) {
sheet.setColumnWidth(i, newWidth);
} else {
sheet.setColumnWidth(i, orgWidth);
}
}
}
设置边框
private static void setBorder(XSSFCellStyle style, BorderStyle border, XSSFColor color) {
style.setBorderTop(border);
style.setBorderLeft(border);
style.setBorderRight(border);
style.setBorderBottom(border);
//color 为边框颜色
style.setBorderColor(XSSFCellBorder.BorderSide.TOP, color);
style.setBorderColor(XSSFCellBorder.BorderSide.LEFT, color);
style.setBorderColor(XSSFCellBorder.BorderSide.RIGHT, color);
style.setBorderColor(XSSFCellBorder.BorderSide.BOTTOM, color);
}
设置颜色
private static XSSFColor createXssfColor(String color) {
//可自定义颜色
return new XSSFColor(Color.BLACK);
}
建立标题栏 |
public static int writeTitlesToExcel(XSSFWorkbook wb, Sheet sheet, List<String> titles) {
int rowIndex = 0;
//获取字体
Font titleFont = wb.createFont();
//设置字体名称(宋体)
titleFont.setFontName("simsun");
//设置字体加粗
// titleFont.setBold(true);
//设置字体颜色 黑色
titleFont.setColor(IndexedColors.BLACK.index);
//获取单元格样式
XSSFCellStyle titleStyle = wb.createCellStyle();
//设置单元格的水平对齐类型(这里是水平居中)
titleStyle.setAlignment(HorizontalAlignment.CENTER);
//设置单元格的垂直对齐类型(这里是居中)
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
//指定图案和纯色单元格填充的单元格填充信息(实心前景)
// titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
//设置字体样式
titleStyle.setFont(titleFont);
//设置边框
setBorder(titleStyle, BorderStyle.THIN, createXssfColor("#000000"));
//在该工作簿中创建第一行
Row titleRow = sheet.createRow(rowIndex);
int colIndex = 0;
for (String title : titles) {//循环创建列
Cell cell = titleRow.createCell(colIndex);
cell.setCellValue(title);
cell.setCellStyle(titleStyle);
colIndex++;
}
//将行数++ 返回用于下面添加数据
rowIndex++;
return rowIndex;
}
导入数据 |
private static int writeRowsToExcel(XSSFWorkbook wb, Sheet sheet, List<List<Object>> rows, int rowIndex) {
Font dataFont = wb.createFont();//获取字体
dataFont.setFontName("simsun");//设置字体名称(宋体)
dataFont.setColor(IndexedColors.BLACK.index);//设置字体颜色 黑色
XSSFCellStyle dataStyle = wb.createCellStyle();//获取单元格样式
//设置单元格的水平对齐类型(这里是水平居中)
dataStyle.setAlignment(HorizontalAlignment.CENTER);
//设置单元格的垂直对齐类型(这里是居中)
dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
dataStyle.setFont(dataFont);//设置字体样式
//设置边框样式(细线、黑色)
setBorder(dataStyle, BorderStyle.THIN, createXssfColor("#000000"));
for (List<Object> rowData : rows) {
Row dataRow = sheet.createRow(rowIndex);
//设置单元格高度
dataRow.setHeight((short) 1000);
int colIndex = 0;
for (Object cellData : rowData) {
Cell cell = dataRow.createCell(colIndex);
//插入照片
if (colIndex == 1 && null != cellData) {
FileOutputStream fileOut = null;
BufferedImage bufferImg = null;
//先把读进来的图片放到一个ByteArrayOutputStream中,以便产生ByteArray
try {
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
//cellData为照片路径
bufferImg = ImageIO.read(new File((String) cellData));
ImageIO.write(bufferImg, "jpg", byteArrayOut);
//画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
Drawing drawing = sheet.createDrawingPatriarch();
//位置后四个参数: 前两个: 图片左上角的X,Y坐标 后两个:图片右下左上角的X,Y坐标
XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, colIndex, rowIndex, colIndex + 1, rowIndex + 1);
anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE);
drawing.createPicture(anchor, wb.addPicture(byteArrayOut.toByteArray(), XSSFWorkbook.PICTURE_TYPE_JPEG));
} catch (Exception e) {
e.printStackTrace();
}
} else {
cell.setCellValue((cellData != null ? cellData.toString() : ""));
}
cell.setCellStyle(dataStyle);
colIndex++;
}
rowIndex++;
}
return rowIndex;
}
对标题和数据一起进行处理 |
public static void writeExcel(XSSFWorkbook wb, Sheet sheet, ExportAnswerXls data) {
int rowIndex = 0;
rowIndex = writeTitlesToExcel(wb, sheet, data.getTitles());
writeRowsToExcel(wb, sheet, data.getRows(), rowIndex);
autoSizeColumns(sheet, data.getTitles().size() + 1);
}