方法一:使用Apache POI 和IText库
步骤1.在build.gradle中导入相关依赖
compile('org.apache.poi:poi:4.1.0')
compile('org.apache.poi:poi-ooxml:4.1.0')
compile('com.itextpdf:itextpdf:5.5.13')
compile('com.itextpdf:itext-asian:5.2.0')
步骤2.编写相关工具类
package com.zo.utils
import com.itextpdf.text.*
import com.itextpdf.text.pdf.*
import org.apache.poi.hssf.usermodel.HSSFDateUtil
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.DateUtil
import org.apache.poi.xssf.usermodel.XSSFCell
import org.apache.poi.xssf.usermodel.XSSFSheet
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.io.ByteArrayOutputStream
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.text.DecimalFormat
object ExcelToPdfUtil {
/**
* 将excel转化成pdf
* @sourceExcelPath: excel全路径
* @targetPdfPath: pdf目标全路径
*/
fun excelToPdf(sourceExcelPath: String, targetPdfPath: String) {
// 读取excel文件到流中
val inputStream = FileInputStream(sourceExcelPath)
val workbook = XSSFWorkbook(inputStream)
// 获取excel的工作表数量
val numberOfSheets = workbook.numberOfSheets
val list = mutableListOf<ByteArray>()
for (i in 0 until numberOfSheets) {
// 获取当前索引的工作表
val sheet = workbook.getSheetAt(i)
val stream = ByteArrayOutputStream()
// 设置PDF纸张大小
val document = Document(PageSize.A4)
PdfWriter.getInstance(document, stream)
// 设置页边距
document.setMargins(0F, 0F, 0F, 10F)
document.open()
// 获取excel每列宽度占比
val widths = getColWidth(sheet)
// 初始化pdf中每列的宽度
val pdfPTable = PdfPTable(widths)
// 设置表格将在页面中占据的宽度百分比
pdfPTable.widthPercentage = 98F
val colCount = widths.size
// 开始遍历excel内容并绘制pdf
for (r in sheet.firstRowNum until sheet.physicalNumberOfRows) {
val row = sheet.getRow(r)
if (row != null && !row.zeroHeight) {
var c = row.firstCellNum.toInt()
while (c < if (row.lastCellNum > colCount) colCount else row.lastCellNum.toInt()) {
if (c >= row.physicalNumberOfCells) {
val pdfPCell = PdfPCell(Phrase(""))
pdfPCell.border = 0
pdfPTable.addCell(pdfPCell)
c += 1
continue
}
val excelCell = row.getCell(c)
var value = ""
if (excelCell != null) {
value = getCellValue(excelCell).toString()
}
val bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED)
//创建Font对象,将基础字体对象,字体大小,字体风格
val font = Font(bf, 12F, Font.NORMAL)
val pCell = PdfPCell(Paragraph(value, font))
val hasBorder = hasBorder(excelCell)
if (!hasBorder) {
pCell.border = 0
}
if (excelCell == null) {
pCell.horizontalAlignment = Element.ALIGN_CENTER
pCell.verticalAlignment = Element.ALIGN_CENTER
} else {
pCell.horizontalAlignment = getHorAlign(excelCell.cellStyle.alignment.code.toInt())
pCell.verticalAlignment = getVerAlign(excelCell.cellStyle.verticalAlignment.code.toInt())
}
pCell.minimumHeight = row.heightInPoints
if (isMergedRegion(sheet, r, c)) {
val span = getMergedSpan(sheet, r, c)
if (span[0] == 1 && span[1] == 1) { //忽略合并过的单元格
c += 1
continue
}
pCell.rowspan = span[0]
pCell.colspan = span[1]
//合并过的列直接跳过
c = c + span[1] - 1
}
pdfPTable.addCell(pCell)
c += 1
}
} else {
val pCell = PdfPCell(Phrase(""))
pCell.border = 0
pCell.minimumHeight = 13F
pdfPTable.addCell(pCell)
}
}
document.add(pdfPTable)
document.close()
val pdfByte = stream.toByteArray()
list.add(pdfByte)
stream.close()
}
val document: Document
val copy: PdfCopy
var reader: PdfReader? = null
try {
document = Document(PdfReader(list[0]).getPageSize(1))
copy = PdfCopy(document, FileOutputStream(targetPdfPath))
document.open()
for (i in 0 until list.size) {
reader = PdfReader(list[i])
val numberOfPages = reader.numberOfPages
for (j in 1..numberOfPages) {
document.newPage()
val page = copy.getImportedPage(reader, j)
copy.addPage(page)
}
}
} catch (e: IOException) {
error("异常")
}
document.close()
copy.close()
reader!!.close()
}
/**
* 获取excel中每列宽度的占比
*/
private fun getColWidth(sheet: XSSFSheet): FloatArray {
val rowNum: Int = getMaxColRowNum(sheet)
val row = sheet.getRow(rowNum)
val cellCount = row.physicalNumberOfCells
val colWidths = arrayOf(cellCount)
var sum = 0
for (i in row.firstCellNum until cellCount) {
val cell = row.getCell(i)
if (cell != null) {
colWidths[i] = sheet.getColumnWidth(i)
sum += sheet.getColumnWidth(i)
}
}
val colWidthPer = floatArrayOf(cellCount.toFloat())
for (i in row.firstCellNum until cellCount) {
colWidthPer[i] = colWidths[i].toFloat() / sum * 100
}
return colWidthPer
}
/**
* 获取excel中列数最多的行号
*/
private fun getMaxColRowNum(sheet: XSSFSheet): Int {
var rowNum = 0
var maxCol = 0
for (r in sheet.firstRowNum until sheet.physicalNumberOfRows) {
val row = sheet.getRow(r)
if (row != null && maxCol < row.physicalNumberOfCells) {
maxCol = row.physicalNumberOfCells
rowNum = r
}
}
return rowNum
}
/**
* 获取单元格值
*/
private fun getCellValue(cell: Cell): Any? {
var result: Any? = ""
try {
if (cell.cellType === CellType.NUMERIC || cell.cellType === CellType.FORMULA) {
result = cell.numericCellValue
result = if (HSSFDateUtil.isCellDateFormatted(cell)) {
// POI Excel 日期格式转换
DateUtil.getJavaDate(result)
} else {
DecimalFormat("0.0").format(result)
}
} else if (cell.cellType === CellType.STRING) {
result = cell.stringCellValue
} else if (cell.cellType === CellType.BOOLEAN) {
result = cell.booleanCellValue
} else if (cell.cellType === CellType.ERROR) {
result = cell.errorCellValue
}
} catch (e: Exception) {
return result
}
return result
}
/**
* 判断excel单元格是否有边框
*/
private fun hasBorder(excelCell: XSSFCell): Boolean {
val top = excelCell.cellStyle.borderTop.code
val bottom = excelCell.cellStyle.borderBottom.code
val left = excelCell.cellStyle.borderLeft.code
val right = excelCell.cellStyle.borderRight.code
return top + bottom + left + right > 2
}
/**
* 获取excel单元格数据显示格式
*/
@Throws(Exception::class)
private fun getNumStyle(dataFormat: String): String {
if (dataFormat.isEmpty()) {
throw Exception("")
}
return if (dataFormat.indexOf("%") > -1) {
dataFormat
} else {
dataFormat.substring(0, dataFormat.length - 2)
}
}
/**
* 判断单元格是否是合并单元格
*/
private fun isMergedRegion(sheet: XSSFSheet, row: Int, column: Int): Boolean {
val sheetMergeCount = sheet.numMergedRegions
for (i in 0 until sheetMergeCount) {
val range = sheet.getMergedRegion(i)
val firstColumn = range.firstColumn
val lastColumn = range.lastColumn
val firstRow = range.firstRow
val lastRow = range.lastRow
if (row in firstRow..lastRow) {
if (column in firstColumn..lastColumn) {
return true
}
}
}
return false
}
/**
* 计算合并单元格合并的跨行跨列数
*/
private fun getMergedSpan(sheet: XSSFSheet, row: Int, column: Int): IntArray {
val sheetMergeCount = sheet.numMergedRegions
val span = intArrayOf(1, 1)
for (i in 0 until sheetMergeCount) {
val range = sheet.getMergedRegion(i)
val firstColumn = range.firstColumn
val lastColumn = range.lastColumn
val firstRow = range.firstRow
val lastRow = range.lastRow
if (firstColumn == column && firstRow == row) {
span[0] = lastRow - firstRow + 1
span[1] = lastColumn - firstColumn + 1
break
}
}
return span
}
/**
* excel垂直对齐方式映射到pdf对齐方式
*/
private fun getVerAlign(align: Int): Int {
return when (align) {
1 -> Element.ALIGN_MIDDLE
2 -> Element.ALIGN_BOTTOM
3 -> Element.ALIGN_TOP
else -> Element.ALIGN_MIDDLE
}
}
/**
* excel水平对齐方式映射到pdf水平对齐方式
*/
private fun getHorAlign(align: Int): Int {
return when (align) {
2 -> Element.ALIGN_CENTER
3 -> Element.ALIGN_RIGHT
1 -> Element.ALIGN_LEFT
else -> Element.ALIGN_CENTER
}
}
/**
* 格式化数字
*/
private fun numFormat(pattern: String, num: Double): String? {
val format = DecimalFormat(pattern)
return format.format(num)
}
}
该方法可以处理具有多个工作表(sheet)的excel文件,将excel生成一个对应的pdf文件