EasyExecl导出百分数(%)这么简单,你搞那么久都搞不好!

最近手上事情比较多,好几个系统排着开发计划,所以,引入了一些外包资源。主要目的是缓解交付压力,由于外包的兄弟不了解业务,就先安排一些小需求,慢慢入坑。前两天,业务提了几个小优化需求,其中就是想把之前导出的报表中有占比的字段,想要导出为百分号,我就想这个小需求简单吧,让外包兄弟试试。可是,搞了一下午,他放弃了,说搞不了。

我听着就想,这不就是加个百分号吗?用EasyExecl很简单啊。我还是很客气的说到,那算了,我来弄吧。然后就花了几分钟时间,轻松处理了。

其实,用EasyExcel导出真的很简单,这里有两种快速的方式

注解

EasyExcel已经提供了NumberFormat注解,我们只需要在需要导出的字段上加该注解即可,该注解有两个参数:

  • value():指定数字格式模式,参照 java.text.DecimalFormat 的格式语法
  • roundingMode():指定舍入模式,默认为 RoundingMode.HALF_UP(四舍五入)

格式模式说明
NumberFormat 注解的 value 参数支持 java.text.DecimalFormat 的格式语法:

  • 表示一个可选数字

  • 0 表示一个必须的数字,如果相应位置没有数字则显示 0
  • . 表示小数点
  • , 表示千位分隔符
  • % 表示百分比
  • E 表示科学计数法
    常用格式示例:
  • #.## - 保留最多两位小数
  • #,###.## - 使用千位分隔符并保留最多两位小数
  • 0.00 - 显示小数点后两位,不足补0
  • #.##% - 以百分比形式显示,保留两位小数

先创建一个导出类并加上注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AnnotationExportData {

/**
* ID
*/
@ExcelProperty("ID")
private Long id;

/**
* 名称
*/
@ExcelProperty("名称")
private String name;

/**
* 整数值
*/
@ExcelProperty("整数值")
private Integer intValue;

/**
* 小数值
*/
@ExcelProperty("小数值")
@NumberFormat("#.##")
private Double doubleValue;

/**
* 百分比值(使用注解格式化为百分比)
*/
@ExcelProperty("百分比值")
@NumberFormat("0.00%")
private Double percentage;

/**
* 日期
*/
@ExcelProperty("创建时间")
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
private Date createTime;
}

构建模拟数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private List<AnnotationExportData> generateAnnotationExportData() {
List<AnnotationExportData> dataList = new ArrayList<>();

// 生成10条测试数据
for (long i = 1; i <= 10; i++) {
dataList.add(AnnotationExportData.builder()
.id(i)
.name("测试数据" + i)
.intValue((int) (i * 10))
.doubleValue(i * 10.5)
.percentage(i * 0.1) // 10%, 20%, 30%...
.createTime(new Date())
.build());
}

return dataList;
}

进行导出:

1
2
3
4
5
// 准备数据
List<AnnotationExportData> dataList = generateAnnotationExportData();

// 导出Excel
ExcelUtil.export(response, dataList, "注解方式导出", "数据", AnnotationExportData.class);

ExcelUtil工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
@Slf4j
public class ExcelUtil {

/**
* 导出Excel
*
* @param response HttpServletResponse
* @param data 数据列表
* @param fileName 文件名
* @param sheetName sheet名
* @param clazz 数据类型
* @param <T> 泛型
*/
public static <T> void export(HttpServletResponse response, List<T> data, String fileName,
String sheetName, Class<T> clazz) {
try {
// 设置响应头
setExcelResponseHeader(response, fileName);

// 导出Excel
EasyExcel.write(response.getOutputStream(), clazz)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.sheet(sheetName)
.doWrite(data);

log.info("Excel导出成功,文件名:{},数据量:{}", fileName, data.size());
} catch (IOException e) {
log.error("Excel导出失败", e);
throw new RuntimeException("Excel导出失败", e);
}
}

/**
* 导出Excel(带自定义处理器)
*
* @param response HttpServletResponse
* @param data 数据列表
* @param fileName 文件名
* @param sheetName sheet名
* @param clazz 数据类型
* @param handlers 自定义处理器列表
* @param <T> 泛型
*/
public static <T> void exportWithHandlers(HttpServletResponse response, List<T> data, String fileName,
String sheetName, Class<T> clazz, List<?> handlers) {
try {
// 设置响应头
setExcelResponseHeader(response, fileName);

// 创建ExcelWriter
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), clazz)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.build();

// 注册自定义处理器
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
for (Object handler : handlers) {
//writeSheet.(handler);
}

// 写入数据
excelWriter.write(data, writeSheet);
excelWriter.finish();

log.info("Excel导出成功(带自定义处理器),文件名:{},数据量:{}", fileName, data.size());
} catch (IOException e) {
log.error("Excel导出失败", e);
throw new RuntimeException("Excel导出失败", e);
}
}

/**
* 使用模板导出Excel
*
* @param response HttpServletResponse
* @param templatePath 模板路径
* @param data 数据
* @param fileName 文件名
*/
public static void exportWithTemplate(HttpServletResponse response, String templatePath,
Map<String, Object> data, String fileName) {
try {
// 设置响应头
setExcelResponseHeader(response, fileName);

// 获取模板输入流
InputStream templateInputStream = ExcelUtil.class.getClassLoader().getResourceAsStream(templatePath);
if (templateInputStream == null) {
throw new RuntimeException("模板文件不存在:" + templatePath);
}

// 填充模板
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(templateInputStream).build();
WriteSheet writeSheet = EasyExcel.writerSheet().build();

// 设置填充配置
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();

// 填充数据
excelWriter.fill(data, fillConfig, writeSheet);
excelWriter.finish();

log.info("Excel模板导出成功,文件名:{}", fileName);
} catch (IOException e) {
log.error("Excel模板导出失败", e);
throw new RuntimeException("Excel模板导出失败", e);
}
}

/**
* 设置Excel响应头
*
* @param response HttpServletResponse
* @param fileName 文件名
* @throws UnsupportedEncodingException 不支持的编码异常
*/
private static void setExcelResponseHeader(HttpServletResponse response, String fileName)
throws UnsupportedEncodingException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");

// 防止中文乱码
String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName + ".xlsx");
}
}

最终效果

模版

这里我们实现SheetWriteHandler拦截器

EasyExecl导出百分数(%)这么简单,你搞那么久都搞不好!

https://blogs.52fx.biz/posts/4006212513.html

作者

eyiadmin

发布于

2025-05-13

更新于

2025-05-16

许可协议

评论