- 作 者:是江迪呀
- ✒️本文关键词:
Java
、Excel
、导出
、工具类
、后端
- ☀️每日 一言:有些事情不是对的才去坚持,而是坚持了它才是对的!
我们在日常开发中,一定遇到过要将数据导出为Excel
的需求,那么怎么做呢?在做之前,我们需要思考下Excel
的组成。Excel
是由四个元素组成的分别是:WorkBook(工作簿)
、Sheet(工作表)
、Row(行)
、Cell(单元格)
,其中包含关系是从左至右,,一个WorkBook
可以包含多个Sheet
,一个Sheet
又是由多个Row
组成,一个Row
是由多个Cell
组成。知道这些后那么我们就使用java
来将数据以Excel
的方式导出。让我们一起来学习吧✏️!
Apache POI
依赖使用Java
实现将数据以Excel
的方式导出,需要依赖第三方的库。我们需要再pom.xml
中引入下面的依赖:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
&
步骤Excel
的元素WokrBook
Workbook workbook = new XSSFWorkbook();
Sheet
Sheet sheet = workbook.createSheet();
设置sheet
的名称
Sheet sheet = workbook.createSheet("sheet名称");
Row
Row row = sheet.createRow(0);
Cell
Cell cell = row.createCell(0, CellType.STRING);
可以指定单元格的类型,支持的类型有下面7种:
_NONE(-1),
NUMERIC(0),
STRING(1),
//公式
FORMULA(2),
BLANK(3),
//布尔
BOOLEAN(4),
ERROR(5);
cell.setCellValue("苹果");
如果我们需要导出的Excel
美观一些,如设置字体的样式加粗、颜色、大小等等,就需要创建样式和字体。
创建样式:
CellStyle cellStyle = workbook.createCellStyle();
//左右居中
excelTitleStyle.setAlignment(HorizontalAlignment.CENTER);
// 设置垂直居中
excelTitleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
创建加粗样式并设置到CellStyle
中:
Font font = workbook.createFont();
//字体颜色为红色
font.setColor(IndexedColors.RED.getIndex());
//字体加粗
font.setBold(true);
cellStyle.setFont(font);
指定Cell
单元格使用该样式:
cell.setCellStyle(style);
Sheet sheet = workbook.createSheet();
//自动调整列的宽度来适应内容
sheet.autoSizeColumn(int column);
// 设置列的宽度
sheet.setColumnWidth(2, 20 * 256);
autoSizeColumn()
传递的参数就是要设置的列索引。setColumnWidth()
第一个参数是要设置的列索引,第二参数是具体的宽度值,宽度 = 字符个数 * 256(例如20个字符的宽度就是20 * 256)
Font font = workbook.createFont();
font.setItalic(boolean italic); 设置倾斜
font.setUnderline(byte underline); 设置下划线
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet(fileName);
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 5));
CellRangeAddress()
方法四个参数分别是fristRow
:起始行、lastRow
:结束行、fristCol
:起始列、lastCol
:结束列。CellRangeAddress(0,1,0,10)
。//创建数据验证
DataValidationHelper dvHelper = sheet.getDataValidationHelper();
//创建要添加校验的单元格对象
CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 10);
//创建必填校验规则
DataValidationConstraint constraint = validationHelper.createCustomConstraint("NOT(ISBLANK(A1))");
//设置校验
DataValidation validation = dvHelper.createValidation(constraint, addressList);
//校验不通过 提示
validation.setShowErrorBox(true);
sheet.addValidationData(validation);
CellRangeAddressList()
方法传递四个参数,分别是:fristRow
:起始行、lastRow
:结束行、fristCol
:起始列、lastCol
:结束列。CellRangeAddressList(0, 0, 0, 10)
表示的就是给第一行从第一列开始到第十列一共十个单元格添加数据校验。//创建SUM公式
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Cell sumCell = row.createCell(0);
sumCell.setCellFormula("SUM(A1:A10)");
//计算SUM公式结果
Cell sumResultCell = row.createCell(1);
sumResultCell.setCellValue(evaluator.evaluate(sumCell).getNumberValue());
//创建AVERAGE公式
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Cell averageCell = row.createCell(0);
averageCell.setCellFormula("AVERAGE(A1:A10)");
//计算AVERAGE公式结果
Cell averageResultCell = row.createCell(1);
averageResultCell.setCellValue(evaluator.evaluate(averageCell).getNumberValue());
//创建COUNT公式
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Cell countCell = row.createCell(0);
countCell.setCellFormula("COUNT(A1:A10)");
//计算COUNT公式结果
Cell countResultCell = row.createCell(1);
countResultCell.setCellValue(evaluator.evaluate(countCell).getNumberValue());
//创建IF公式
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Cell ifCell = row.createCell(0);
ifCell.setCellFormula("IF(A1>B1,\"Yes\",\"No\")");
//计算IF公式结果
Cell ifResultCell = row.createCell(1);
ifResultCell.setCellValue(evaluator.evaluate(ifCell).getStringValue());
//创建CONCATENATE公式
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Cell concatenateCell = row.createCell(0);
concatenateCell.setCellFormula("CONCATENATE(A1,\" \",B1)");
//计算CONCATENATE公式结果
Cell concatenateResultCell = row.createCell(1);
concatenateResultCell.setCellValue(evaluator.evaluate(concatenateCell).getStringValue());
//下拉值
private List<String> grade = Arrays.asList("高", "中", "低");
(此处省略n行代码)
Sheet sheet = workbook.createSheet("sheet");
DataValidation dataValidation = this.addPullDownConstraint(i, sheet, grade );
sheet.addValidationData(dataValidation);
// 设置单元格样式 - 数字格式
CellStyle numberCellStyle = workbook.createCellStyle();
numberCellStyle.setDataFormat(workbook.createDataFormat().getFormat("#,##0.00"));
//指定单元格
Row row = sheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellStyle(numberCellStyle);
// 设置单元格样式 - 日期格式
CellStyle dateCellStyle = workbook.createCellStyle();
dateCellStyle.setDataFormat(workbook.createDataFormat().getFormat("yyyy-MM-dd"));
//指定单元格
Row row = sheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellStyle(dateCellStyle);
下面的示例使用SpringBoot
项目来演示:
pom.xml
依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>2.7.5version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
<version>2.7.5version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
<version>4.1.2version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxmlartifactId>
<version>4.1.2version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.16.16version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>2.0.21version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.12.0version>
dependency>
Controller
层代码:
package shijiangdiya.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import shijiangdiya.utils.ExportUtils;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/sync")
public class ExportController {
}
@Autowired
private HttpServletResponse response;
@PostMapping("/export")
public void export() {
//模拟json数据
String data = "[{\n" +
" \"studentId\": \"20210101\",\n" +
" \"name\": \"Alice\",\n" +
" \"age\": 20,\n" +
" \"credit\": 80\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210102\",\n" +
" \"name\": \"Bob\",\n" +
" \"age\": 21,\n" +
" \"credit\": 85\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210103\",\n" +
" \"name\": \"Charlie\",\n" +
" \"age\": 22,\n" +
" \"credit\": 90\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210104\",\n" +
" \"name\": \"David\",\n" +
" \"age\": 20,\n" +
" \"credit\": 75\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210105\",\n" +
" \"name\": \"Emily\",\n" +
" \"age\": 21,\n" +
" \"credit\": 82\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210106\",\n" +
" \"name\": \"Frank\",\n" +
" \"age\": 22,\n" +
" \"credit\": 88\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210107\",\n" +
" \"name\": \"Grace\",\n" +
" \"age\": 20,\n" +
" \"credit\": 81\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210108\",\n" +
" \"name\": \"Henry\",\n" +
" \"age\": 21,\n" +
" \"credit\": 89\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210109\",\n" +
" \"name\": \"Isaac\",\n" +
" \"age\": 22,\n" +
" \"credit\": 92\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210110\",\n" +
" \"name\": \"John\",\n" +
" \"age\": 20,\n" +
" \"credit\": 78\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210111\",\n" +
" \"name\": \"Kelly\",\n" +
" \"age\": 21,\n" +
" \"credit\": 84\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210112\",\n" +
" \"name\": \"Linda\",\n" +
" \"age\": 22,\n" +
" \"credit\": 87\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210113\",\n" +
" \"name\": \"Mike\",\n" +
" \"age\": 20,\n" +
" \"credit\": 77\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210114\",\n" +
" \"name\": \"Nancy\",\n" +
" \"age\": 21,\n" +
" \"credit\": 83\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210115\",\n" +
" \"name\": \"Oscar\",\n" +
" \"age\": 22,\n" +
" \"credit\": 91\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210116\",\n" +
" \"name\": \"Paul\",\n" +
" \"age\": 20,\n" +
" \"credit\": 76\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210117\",\n" +
" \"name\": \"Queen\",\n" +
" \"age\": 21,\n" +
" \"credit\": 86\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210118\",\n" +
" \"name\": \"Rachel\",\n" +
" \"age\": 22,\n" +
" \"credit\": 94\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210119\",\n" +
" \"name\": \"Sarah\",\n" +
" \"age\": 20,\n" +
" \"credit\": 79\n" +
" },\n" +
" {\n" +
" \"studentId\": \"20210120\",\n" +
" \"name\": \"Tom\",\n" +
" \"age\": 21,\n" +
" \"credit\": 80\n" +
" }\n" +
"]\n";
ExportUtils.exportExcel("学生信息", data, Student.class, response);
}
/**
* 数据导出
* @param fileName 导出excel名称
* @param data 导出的数据
* @param c 导出数据的实体class
* @param response 响应
* @throws Exception
*/
public static void exportExcel(String fileName, String data, Class<?> c, HttpServletResponse response) throws Exception {
try {
// 创建表头
// 创建工作薄
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet();
// 创建表头行
Row rowHeader = sheet.createRow(0);
if (c == null) {
throw new RuntimeException("Class对象不能为空!");
}
Field[] declaredFields = c.getDeclaredFields();
List<String> headerList = new ArrayList<>();
if (declaredFields.length == 0) {
return;
}
for (int i = 0; i < declaredFields.length; i++) {
Cell cell = rowHeader.createCell(i, CellType.STRING);
String headerName = String.valueOf(declaredFields[i].getName());
cell.setCellValue(headerName);
headerList.add(i, headerName);
}
// 填充数据
List<?> objects = JSONObject.parseArray(data, c);
Object obj = c.newInstance();
if (!CollectionUtils.isEmpty(objects)) {
for (int o = 0; o < objects.size(); o++) {
Row rowData = sheet.createRow(o + 1);
for (int i = 0; i < headerList.size(); i++) {
Cell cell = rowData.createCell(i);
Field nameField = c.getDeclaredField(headerList.get(i));
nameField.setAccessible(true);
String value = String.valueOf(nameField.get(objects.get(o)));
cell.setCellValue(value);
}
}
}
response.setContentType("application/vnd.ms-excel");
String resultFileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + resultFileName + ";" + "filename*=utf-8''" + resultFileName);
workbook.write(response.getOutputStream());
workbook.close();
response.flushBuffer();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@PostMapping("/import")
public void importExcel(@RequestParam("excel") MultipartFile excel){
Workbook workbook = null;
try {
workbook = WorkbookFactory.create(excel.getInputStream());
Sheet sheet = workbook.getSheetAt(0);
List<Student> students = new ArrayList<>();
int i = 0;
for (Row row : sheet) {
Row row1 = sheet.getRow(i + 1);
if(row1 != null){
Student data = new Student();
data.setStudentId(Integer.parseInt(row1.getCell(0).getStringCellValue()));
data.setName(row1.getCell(1).getStringCellValue());
data.setAge(Integer.parseInt(row1.getCell(2).getStringCellValue()));
data.setCredit(Integer.parseInt(row1.getCell(3).getStringCellValue()));
students.add(data);
}
}
System.out.println(students);
workbook.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
/**
* 导入
* @param workbook 工作簿
* @param c 实体类
* @return 实体类集合
*/
public static <T> List<T> importExcel(Workbook workbook,Class<?> c){
List<T> dataList = new ArrayList<>();
try {
Sheet sheet = workbook.getSheetAt(0);
int i = 0;
T o = null;
for (Row row : sheet) {
Row row1 = sheet.getRow(i + 1);
if(row1 != null){
o = (T) c.newInstance();
Field[] declaredFields = c.getDeclaredFields();
for (int i1 = 0; i1 < declaredFields.length; i1++) {
String name = declaredFields[i1].getName();
Field declaredField1 = o.getClass().getDeclaredField(name);
declaredField1.setAccessible(true);
Cell cell = row1.getCell(i1);
String type = declaredFields[i1].getType().getName();
String value = String.valueOf(cell);
if(StringUtils.equals(type,"int") || StringUtils.equals(type,"Integer")){
declaredField1.set(o,Integer.parseInt(value));
} else if(StringUtils.equals(type,"java.lang.String") || StringUtils.equals(type,"char") || StringUtils.equals(type,"Character") ||
StringUtils.equals(type,"byte") || StringUtils.equals(type,"Byte")){
declaredField1.set(o,value);
} else if(StringUtils.equals(type,"boolean") || StringUtils.equals(type,"Boolean")){
declaredField1.set(o,Boolean.valueOf(value));
} else if(StringUtils.equals(type,"double") || StringUtils.equals(type,"Double")){
declaredField1.set(o,Double.valueOf(value));
} else if (StringUtils.equals(type,"long") || StringUtils.equals(type,"Long")) {
declaredField1.set(o,Long.valueOf(value));
} else if(StringUtils.equals(type,"short") || StringUtils.equals(type,"Short")){
declaredField1.set(o,Short.valueOf(value));
} else if(StringUtils.equals(type,"float") || StringUtils.equals(type,"Float")){
declaredField1.set(o,Float.valueOf(value));
}
}
}
dataList.add(o);
}
workbook.close();
return dataList;
}catch (Exception e){
e.printStackTrace();
}
return dataList;
}
注意:导入工具类仅限Java的八大基础数据类型
和String
类型。如果还有其他类型需要自己扩展。