Upload Or Download Excel(.xls/.xlsx) File In Kotlin Ⅰ

先前有聊过上传下载CSV文件时,挖了个Excel的坑,今天咱们就填一下.首先咱们使用的是阿帕奇的POI库,

gradle: compile("org.apache.poi:poi-ooxml:4.1.0")

在学习之前建议有必要回读前面的导出三连其中些知识点不在侧重,这里仅叙述实现及调整实现自己的业务,先来看一下上传.xlsx文件模板的样子:

硬编码如下:

	/**
	 * @param fileName 导出文件名
	 * @param datas 导出数据集合
	 * @param onlyWrite default: 仅导出
	 * @param fontName 设置字体 default: 宋体
	 */
	fun write(fileName: String, datas: List<T>, onlyWrite: Boolean = true, fontName: String = "宋体") =
	XSSFWorkbook().use { workbook ->
		val createHelper = workbook.creationHelper

		val sheet = workbook.createSheet(fileName)
		sheet.defaultRowHeight = (sheet.defaultRowHeight * 2).toShort()
		sheet.defaultColumnWidth = sheet.defaultColumnWidth * 2

		val headerFont = workbook.createFont()
		headerFont.fontName = fontName

		val headerCellStyle = workbook.createCellStyle()
		headerCellStyle.setFont(headerFont)

		val cellStyle = workbook.createCellStyle()
		cellStyle.dataFormat = createHelper.createDataFormat().getFormat("@") //设置单元格为文本
		//设置附加属性dataFormat
		for (i in (0..providers.size + 26)) { //最大列数x+26 设置此区域为文本,26为自由列数,用户导入时可填属性值
			sheet.setDefaultColumnStyle(i, cellStyle)
		}
		var titleRow: XSSFRow //标题行
		var rowIdx = 3 //数据开始行
		val filedRow = sheet.createRow(0)
		filedRow.ctRow.hidden = true //隐藏域名行
		titleRow = sheet.createRow(1)

		val infoRow = sheet.createRow(2)
		infoRow.height = (3 * sheet.defaultRowHeight).toShort() //说明行高度设置

		if (onlyWrite) { // 如果仅导出覆盖域名
			titleRow = sheet.createRow(0)
			rowIdx = 1 //数据开始行为1
		}
		titleRow.height = sheet.defaultRowHeight
		// Header
		datas.forEach {
			val row = sheet.createRow(rowIdx++)
			row.height = sheet.defaultRowHeight
			providers.forEachIndexed { i, p ->
				//域值
				val cellFiled = filedRow.createCell(i)
				cellFiled.setCellValue(p.field)
				cellFiled.cellStyle = headerCellStyle
				//标题
				val cellTitle = titleRow.createCell(i)
				if (p.required) { // 必填
					cellTitle.setCellValue(p.title.plus("*")) //必填项加*标识
					cellTitle.cellStyle = workbook.createCellStyle().apply {
						this.setFont(workbook.createFont().also {
							it.fontName = fontName
							it.color = Font.COLOR_RED //必填项字体红色高亮
						})
					}
				} else {
					cellTitle.setCellValue(p.title)
				}
				//说明
				headerCellStyle.wrapText = true
				val infoCell = infoRow.createCell(i)
						infoCell.setCellValue(createHelper.createRichTextString(p.information))
				headerFont.color = IndexedColors.GREY_50_PERCENT.index
				infoCell.cellStyle = headerCellStyle

				//数据
				val rc = row.createCell(i)
				rc.setCellValue(p.func!!.apply(it).toString())
				rc.cellStyle = cellStyle

			}

		}//.createTempFile(fileName, XLSX)
		File.createTempFile(fileName, XLSX).apply {//创建文件时可指出文件地址("/home/xxx/Desktop/customers.xlsx"),这里是临时文件
			FileOutputStream(this).use {
				workbook.write(it) //写出文件
			}
		}


	}

心细的同学可能观察到了,excel的第一行(index:0)给隐藏了,这里开启了:        filedRow.ctRow.hidden = true //隐藏域名行,硬编码中所提到的26是指从第D列往后26列均为用户自由可添加数据值,暂时还没找到设置excel全部(a+All)列为文本的方式.

使用:

在此之前再次提醒复习导出三连,前面所提到的要用先注册,这里也做了增强:

	/**
	 * 注册需要导入的数据属性及数值
	 * @param field 数据属性;若导入模板对象包含对象时filed需驼峰规则设置包含对象的属性名并拼接包含对象的内容属性名称
	 * 模板对象及包含对象所要导入数据属性必须初始化默认值(构造函数)
	 * 如: class A (var b: B = B()); class B (var c: String="", var d: Int = 0)部分属性可如下设置:
	 * filed: "bC", func: Function { it.b.c }
	 * @param required 必填字段设置
	 * @param information 属性格式等要求说明
	 */
	fun register(
			field: String, title: String = "", func: Function<T, Any> = Function { "" }, required: Boolean = false, information: String = ""
	) = providers.add(Provider(field, title, func, required, information)).let { this }

其实增强中所述的field驼峰命名规则是基于导入时相对而言,这里测试的导入方法中用到了ModelMapper映射,如果您欣喜于反射亦可要求您所习惯的方式如:a.b.c的链式调用取值,接下来也会说明下反射方法的实现.

导出或下载:

	/**
	 * 数据下载及模板导出
	 * @param onlyDownload 默认仅用于数据下载,下载导出模板时设置true
	 * @param fontName 设置字体名称 默认宋体
	 */
	fun download(response: HttpServletResponse, fileName: String, datas: List<T>, onlyDownload: Boolean = true, fontName: String = "宋体") {
		DownloadDataUtils.download(response, this.write(fileName, datas, onlyDownload, fontName), fileName.plus(XLSX))
	}

需要说明的是测试我只支持XLSX格式.xls如果您喜欢可自行尝试.

测试:

@Throws(IOException::class)
fun main(args: Array<String>?) {
	ExcelFileUtil<ReadExcel>().register("customerId", "编码", Function { it.customer.id }, true)
			.register("customerName", "姓名", Function { it.customer.name }, true, "姓名必须不能为空;\n必须含有中文字符")
			.register("customerGender", "性别", Function { it.customer.address }).register("customerAge", "年龄", Function { it.customer.age })
			.write("customers", readExcels, false)

	println(ExcelFileUtil<ReadExcel>().read(ReadExcel::class.java, 3, 4, FileInputStream(File("/home/xxx/Desktop/customers.xlsx")), "customers"))
}

这里我直接把文件写在了桌面,而不是经过浏览器(http协议),所以直接调用时需注意.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值