Java 的 POI 库可以用来创建和操作 Excel 表格,有时候我们只需要简单地将 List 或 Map 导出到表格,样板代码比较多,不够优雅。如果能像 Gson 那样,使用注解标记要导出的属性,就方便的多。

Github:https://github.com/imcloudfloating/ListToExcell

POI 的依赖:

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
</dependency>

1. 创建注解

package cloud.list2excel.annotation;

import org.apache.poi.hssf.util.HSSFColor;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column{
String title() default "";
short fontSize() default 14;
HSSFColor.HSSFColorPredefined fontColor() default HSSFColor.HSSFColorPredefined.BLACK;
HSSFColor.HSSFColorPredefined borderColor() default HSSFColor.HSSFColorPredefined.BLACK;
}

创建一个 @Column 注解,用于标记字段

  • title:该字段在表格头部的名称,默认值为属性名。
  • fontSize:字体大小,默认 14px。
  • fontColor:字体颜色,默认黑色。
  • borderColor:边框颜色,默认黑色。

2. 使用反射获取注解,用 POI 将数据写入到表格

这部分用的 Kotlin,但是反射和注解还是用的 Java,因为 Kotlin 反射获取的字段是排过序的,不是声明的顺序。

package cloud.list2excel.util

import cloud.list2excel.annotation.Column
import org.apache.poi.hssf.usermodel.HSSFCellStyle
import org.apache.poi.hssf.usermodel.HSSFSheet
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.ss.usermodel.BorderStyle /**
* List/Map 导出 Excel 表格
* @author Cloud
*/
object ListToExcel { private var workbook: HSSFWorkbook = HSSFWorkbook()
private val cellStyles: MutableList<HSSFCellStyle> = ArrayList() /**
* 处理单个 Sheet
*/
fun from(data: List<Any>): HSSFWorkbook {
toWorkbook("Sheet0", data)
return workbook
} /**
* 处理多个 Sheet
*/
fun from(data: Map<String, List<Any>>): HSSFWorkbook {
if (data.isEmpty())
return workbook for (sheet in data) {
toWorkbook(sheet.key, sheet.value)
} return workbook
} private fun toWorkbook(sheetName: String, list: List<Any>) {
val sheet = workbook.createSheet(sheetName) if (list.isEmpty())
return val headers: MutableList<String> = ArrayList()
val data: MutableList<MutableList<Any>> = ArrayList() // 获取注解并设置表头
for (field in list[0].javaClass.declaredFields) {
field.isAccessible = true val annotation = field.getAnnotation(Column::class.java) if (annotation != null) {
headers.add(if (annotation.title == "") field.name else annotation.title) val cellStyle = workbook.createCellStyle().also { style ->
style.setFont(workbook.createFont().also {
it.fontHeightInPoints = annotation.fontSize
it.color = annotation.fontColor.index
}) } cellStyle.run {
leftBorderColor = annotation.borderColor.index
topBorderColor = annotation.borderColor.index
rightBorderColor = annotation.borderColor.index
bottomBorderColor = annotation.borderColor.index borderLeft = BorderStyle.THIN
borderTop = BorderStyle.THIN
borderRight = BorderStyle.THIN
borderBottom = BorderStyle.THIN
} cellStyles.add(cellStyle)
}
} // 获取数据
for (obj in list) {
val rowData: MutableList<Any> = ArrayList()
for (field in obj.javaClass.declaredFields) {
field.isAccessible = true val annotation = field.getAnnotation(Column::class.java) if (annotation != null) {
val t = field.get(obj)
if (t == null) {
rowData.add("")
} else {
rowData.add(t)
}
}
}
data.add(rowData)
} setHeader(sheet, headers)
setData(sheet, data)
} /**
* 设置表格头
*/
private fun setHeader(sheet: HSSFSheet, headers: List<String>) {
val row = sheet.createRow(0) for (i in headers.indices) {
val cell = row.createCell(i)
cell.setCellValue(headers[i])
cell.setCellStyle(cellStyles[i])
}
} /**
* 写入数据
*/
private fun setData(sheet: HSSFSheet, data: List<List<Any>>) {
for (i in data.indices) {
val row = sheet.createRow(i + 1) for (j in data[i].indices) {
val cell = row.createCell(j)
cell.setCellValue(data[i][j].toString())
cell.setCellStyle(cellStyles[j])
sheet.autoSizeColumn(j)
}
}
}
}

from() 的参数为 List 时,直接写入 workbook 然后返回,为 Map 时,将 Map 中的 List 逐个写入到 workbook,Map 的 key 作为 Sheet 的名称。

3. 使用

创建两个实体类测试:

package cloud.list2excel.util

import cloud.list2excel.annotation.Column
import org.apache.poi.hssf.util.HSSFColor
import java.sql.Date data class Film(
@Column(title = "ID", fontColor = HSSFColor.HSSFColorPredefined.RED)
var id: Int? = null, @Column(title = "Title")
var title: String? = null, @Column(title = "Release Date")
var release_date: Date? = null, @Column(title = "Duration")
var duration: String? = null
)
package cloud.list2excel.util

import cloud.list2excel.annotation.Column
import java.sql.Date data class Actor(
@Column(title = "ID")
var id: Int? = null, @Column(title = "Full Name")
var name: String? = null, @Column(title = "Birth")
var birth: Date?=null
)

测试类:

此处写入了两个 Sheet。

package cloud.list2excel.util

import java.io.File
import java.sql.Date class ListToExcelTest { private val films = listOf(
Film(1, "Iron Man", Date.valueOf("2008-4-30"), "126 min"),
Film(2, "Star Wars: Episode IV - A New Hope", Date.valueOf("1977-5-25"), "121 min"),
Film(3, "Zootropolis", Date.valueOf("2016-3-4"), "109 min")
) private val actors = listOf(
Actor(1, "Robert John Downey Jr.", Date.valueOf("1965-4-4")),
Actor(2, "Mark Hamill", Date.valueOf("1951-9-25")),
Actor(3, "Ginnifer Goodwin", Date.valueOf("1978-5-22"))
) private val data = mapOf(
Pair("films", films),
Pair("actors", actors)
) @org.junit.Test
fun toExcel() {
val before = System.currentTimeMillis()
val workbook = ListToExcel.from(data)
val after = System.currentTimeMillis()
println("Time Usage: ${after - before}ms")
workbook.write(File("/home/data.xls"))
}
}

导出结果:

效率似乎不怎么高 _

List/Map 导出到表格(使用注解和反射)的更多相关文章

  1. Spring Boot 导出Excel表格

    Spring Boot 导出Excel表格 添加支持 <!--添加导入/出表格依赖--> <dependency> <groupId>org.apache.poi& ...

  2. vue 导出excel表格

    对于涉及到数据比较多的管理后台导出excel 表格这个需求就非常的常见了 所以? vue 怎么到处excel表格的? 有两种办法 1:请求接口后台直接给你的是excel文件,你需要做的就是怎么接收ex ...

  3. poi导出word表格详解 超详细了

    转:非常感谢原作者 poi导出word表格详解 2018年07月20日 10:41:33 Z丶royAl 阅读数:36138   一.效果如下 二.js代码 function export_word( ...

  4. Maven项目结合POI导出Excl表格Demo-亲测可用

    Maven项目结合POI导出Excl表格 一.POM文件添加依赖 <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> ...

  5. 从数据库导出数据到excel之List<map>导出

    说明:很多时候取出来的数据是封装为List<Map<String,Object>>,可以直接导出excel表格 项目说明就在 “上一篇” 直接上代码(数据层和业务层不用说了,查 ...

  6. Java基于注解和反射导入导出Excel

    代码地址如下:http://www.demodashi.com/demo/11995.html 1. 构建项目 使用Spring Boot快速构建一个Web工程,并导入与操作Excel相关的POI包以 ...

  7. vue中导出Excel表格

    项目中我们可能会碰到导出Excel文件的需求,一般后台管理系统中居多,将table中展示的数据导出保存到本地.当然我们也可以通过一些处理来修改要导出的数据格式,具体需求具体对待. 1.首先我们需要安装 ...

  8. React+后端实现导出Excle表格的功能

    最近在做一个基于React+antd前端框架的Excel导出功能,我主要在后端做了处理,根据以下步骤,可以很容易就实现导出Excel表格数据的功能. 在做这类导出文件的功能,其实,在后端进行处理,会更 ...

  9. 在vue中导出excel表格

    初学者学习vue开发,想把前端项目中导出Excel表格,查了众多帖子,踩了很多坑,拿出来与大家分享一下经验. 安装依赖 //npm npm install file-saver -S npm inst ...

随机推荐

  1. Jmeter测试技巧

    最近在用Jmeter做接口测试,使用中整理了一些组件的使用技巧. 一. 用户定义的变量 都是全局变量,无论是否在某个线程组或请求内,都是采用最新赋值的内容 二. 固定定时器 在单个请求内是让本请求线程 ...

  2. InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's

    InvalidOperationException: Operations that change non-concurrent collections must have exclusive acc ...

  3. nginx实现tcp的反向代理

     nginx不仅可以实现http的反向代理,同时也支持TCP的反向代理以SSH为例1.编译的时候需要加入--with-stream这个参数,以加载ngx_stream_core_module这个模块2 ...

  4. USACO Chocolate Giving

    洛谷 P2984 [USACO10FEB]给巧克力Chocolate Giving 洛谷传送门 JDOJ 2680: USACO 2010 Feb Silver 2.Chocolate Giving ...

  5. classmethode,staticmethode、反射

    目录 classmethod: staticmethod: classmethod与staticmethod都是python解释器内置的装饰器 类中定义的函数分为两大类:绑定方法和非绑定方法 在类中正 ...

  6. ESA2GJK1DH1K升级篇: STM32远程乒乓升级,升级流程源码详细说明

    前言 1.BootLoader程序,升级简要流程图 2.其实主要的就是把程序文件写入环形队列,然后环形队列取出来数据写入Flash 3.用户程序,简要流程图 下面的读一下,有个印象就可以: 说白了就是 ...

  7. 8-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案安全篇(Apache 配置SSL,HTTPS连接)

    https://www.cnblogs.com/yangfengwu/p/10947423.html 和当时配置MQTT差不多,去下载证书文件   https://www.cnblogs.com/ya ...

  8. loj2245 [NOI2014]魔法森林 LCT

    [NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...

  9. [NOI2010]超级钢琴 主席树

    [NOI2010]超级钢琴 链接 luogu 思路 和12省联考的异或粽子一样. 堆维护n个左端点,每次取出来再放回去次 代码 #include <bits/stdc++.h> #defi ...

  10. 【树状数组】【P5069】[Ynoi2015]纵使日薄西山

    Description 给定一个长度为 \(n\) 的非负整数序列 \(\{a_n\}\),\(q\) 次操作,每次要么单点修改序列某个值,要么查询整个序列需要操作多少次才能变成全 \(0\). 一次 ...