ExcelExportDto为数据返回的类
class ExcelExportDto {
var couponCode: String? = null
var batchName: String? = null
var batchDescription: String? = null
var code: String? = null
}
依赖:
// https://mvnrepository.com/artifact/org.apache.poi/poi
implementation("org.apache.poi:poi:5.2.2")
implementation("org.apache.poi:poi-ooxml:5.2.2")
自定义Excel工具:
import org.apache.poi.hssf.usermodel.HSSFCell
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.ss.usermodel.Font
import org.apache.poi.ss.usermodel.HorizontalAlignment
/**
* @Description :
* @Author xiaomh
* @date 2023/1/10 15:01
*/
class ExlUtils {
fun getHSSFWorkbook(
sheetName: String?,
title: Array<String>,
values: Array<Array<String?>>,
workbook: HSSFWorkbook?
): HSSFWorkbook {
// 创建一个HSSFWorkbook,对应一个Excel文件
var workbook = workbook
if (workbook == null) {
workbook = HSSFWorkbook()
}
// 在workbook中添加一个sheet,对应Excel文件中的sheet
val sheet = workbook.createSheet(sheetName)
val font: Font = workbook.createFont()
// font.fontHeightInPoints = 10.toShort()
font.bold = true
// 在sheet中添加表头第0行
var row = sheet.createRow(0)
// 创建单元格,并设置值表头 设置表头居中
val cellStyle = workbook.createCellStyle()
cellStyle.alignment = HorizontalAlignment.CENTER
cellStyle.setFont(font)
// 声明列对象
var cell: HSSFCell? = null
// 创建标题
for (i in title.indices) {
cell = row.createCell(i)
cell.setCellValue(title[i])
cell.setCellStyle(cellStyle)
}
// 创建内容
for (i in values.indices) {
row = sheet.createRow(i + 1)
when (i) {
0 -> sheet.setColumnWidth(i, pixelWidth(100).toInt())
1 -> sheet.setColumnWidth(i, pixelWidth(100).toInt())
2 -> sheet.setColumnWidth(i, pixelWidth(150).toInt())
3 -> sheet.setColumnWidth(i, pixelWidth(400).toInt())
}
for (j in 0 until values[i].size) {
// 将内容按顺序赋给对应的列对象
row.createCell(j).setCellValue(values[i][j])
}
}
return workbook
}
private fun pixelWidth(pxs: Int): Int {
var width = (EXCEL_COLUMN_WIDTH_FACTOR * (pxs / UNIT_OFFSET_LENGTH))
width += UNIT_OFFSET_MAP[pxs % UNIT_OFFSET_LENGTH]
return width
}
companion object {
const val EXCEL_COLUMN_WIDTH_FACTOR: Short = 256
const val UNIT_OFFSET_LENGTH = 7
val UNIT_OFFSET_MAP = intArrayOf(0, 36, 73, 109, 146, 182, 219)
}
}
导出:
@GET
@Operation(summary = "导出excel表格", description = "导出excel表格")
@Path("/coupon/export/excel/{couponReleaseId}")
// @Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
// @Produces("application/vnd.ms-excel;charset=utf-8")
@Authenticated
fun exportInstanceExcel(@PathParam("couponReleaseId") couponReleaseId: UUID): Response {
val fileContent= excelService.exportInstanceExcel(couponReleaseId)
val dateTime = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())
val filename = URLEncoder.encode("优惠码$dateTime.xls", "UTF-8")
return Response.ok(fileContent)
.header("Access-Control-Expose-Headers", "Content-Disposition")
.header(HttpHeaders.CONTENT_TYPE, "application/vnd.ms-excel;charset=utf-8")
//必须要加这一行,不然前端无法获取
.header(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s", filename))
.build()
}
fun exportInstanceExcel( couponReleaseId: UUID): ByteArray {
// Excel标题
val title = arrayOf("优惠卷编号", "Batch Name", "Batch Description", "优惠码")
// sheet名
val sheetName = "优惠码"
// 将数据放到数组中
val instancePos: List<CouponInstance> = couponInstanceRepository.findByCouponReleaseId(couponReleaseId)
val couponCode = instancePos[0].couponRelease?.coupon?.couponCode
val batchName = instancePos[0].couponRelease?.name
val batchDescription = instancePos[0].couponRelease?.description
val instanceVos: List<ExcelExportDto> = instancePos.stream()
.map { instance ->
val excelExportDto = ExcelExportDto()
excelExportDto.couponCode = couponCode
excelExportDto.batchName = batchName
excelExportDto.batchDescription = batchDescription
excelExportDto.code = instance.code
excelExportDto
}
.collect(Collectors.toList())
val content = Array(instanceVos.size) {
arrayOfNulls<String>(
title.size
)
}
for (i in instanceVos.indices) {
val instanceVo: ExcelExportDto = instanceVos[i]
content[i][0] = instanceVo.couponCode
content[i][1] = instanceVo.batchName
content[i][2] = instanceVo.batchDescription
content[i][3] = instanceVo.code
}
// 导出Excel
try {
val exlUtils = ExlUtils()
val hssfWorkbook = exlUtils.getHSSFWorkbook(sheetName, title, content, null)
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
hssfWorkbook.write(outputStream)
hssfWorkbook.close()
// outputStream.flush()
outputStream.close()
return outputStream.toByteArray()
} catch (e: Exception) {
e.printStackTrace()
}
throw ApplicationException(ErrorCode.UNKNOWN_ERROR)
}
效果
导入:
@POST
@Path("/coupon/import/excel")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Authenticated
fun importInstanceExcel(@MultipartForm formData: FileUploadFormData){
excelService.readExcel(formData.file?.uploadedFile()?.toFile())
}
@Throws(FileNotFoundException::class, IOException::class)
fun readExcel(file: File?): List<Any>? {
// val workbook = HSSFWorkbook(file?.let { FileInputStream(it) })
val workbook = XSSFWorkbook(file?.let { FileInputStream(it) })
//获取工作表,既可以根据工作表的顺序获取,也可以根据工作表的名称获取
val sheet = workbook.getSheetAt(0)
//设置单元格类型,不设置有些number数据会报错
val lastRowNum = sheet.lastRowNum
println(lastRowNum)
for (i in 1..lastRowNum) {
//根据行号获取行对象
val row = sheet.getRow(i)
val lastCellNum = row.lastCellNum
for (j in 0 until lastCellNum) {
val formatter = DataFormatter()
val value = formatter.formatCellValue(row.getCell(j))
print("$value ")
}
println()
}
workbook.close()
return null
}
记录:org.apache.commons:commons-csv导出csv
依赖:
implementation("org.apache.commons:commons-csv:1.10.0")
导出:
@GET
@Operation(summary = "导出scv表格", description = "导出scv表格")
@Path("/coupon/export/csv/test")
// @Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
// @Produces("application/vnd.ms-excel;charset=utf-8")
// @Authenticated
@Produces(MediaType.APPLICATION_OCTET_STREAM)
fun export(): Response {
val csvFile = excelService.exportInstanceCsv()
val filename = URLEncoder.encode("优惠码${LocalDateTime.now()}.csv", "UTF-8")
return Response.ok(csvFile)
.header("Access-Control-Expose-Headers", "Content-Disposition")
.header(HttpHeaders.CONTENT_TYPE, "application/vnd.ms-csv;charset=utf-8")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=$filename")
.build()
}
fun exportInstanceCsv(): ByteArray? {
val instanceVos: MutableList<ExcelExportDto> = mutableListOf()
instanceVos.add(ExcelExportDto().apply {
this.couponCode = "TC001"
this.batchName = "TEST001"
this.batchDescription = "TEST001"
this.code = "HAPPY001"
})
instanceVos.add(ExcelExportDto().apply {
this.couponCode = "TC002"
this.batchName = "TEST002"
this.batchDescription = "TEST002"
this.code = "HAPPY002"
})
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
val csvPrinter = CSVPrinter(
OutputStreamWriter(outputStream),
CSVFormat.DEFAULT.withHeader(
"优惠卷编号", "Batch Name", "Batch Description", "优惠码"
)
)
for (instanceVo in instanceVos) {
csvPrinter.printRecord(
instanceVo.couponCode,
instanceVo.batchName,
instanceVo.batchDescription,
instanceVo.code
)
}
csvPrinter.flush()
csvPrinter.close()
outputStream.close()
return outputStream.toByteArray()
}