我正在尝试使用 grails 自定义渲染器来使用 apache-poi 库渲染 Excel XLSX 文件。我做了一个渲染器类
class APIReportXLSXRenderer extends AbstractRenderer<APIReport> {
APIReportXLSXRenderer() {
super(APIReport, [new MimeType("application/vnd.ms-excel", "xlsx")] as MimeType[])
}
@Override
void render(APIReport output, RenderContext context) {
context.contentType = GrailsWebUtil.getContentType("application/vnd.ms-excel", GrailsWebUtil.DEFAULT_ENCODING)
def items = output.getItems()
def fields = output.getFields()
def headers = (fields.keySet() + items[0].keySet()) as List
// convert maps to list of values each in order of the headers
def values = (items ?: []).collect { Map item -> headers.collect { String h -> item?.containsKey(h) ? item[h] : output[h] } }
def wos = new WriterOutputStream(context.writer)
createXLSXFile(headers, values, wos) // FIXME: This currently produces corrupt files.
}
// Lifted from ApiController
private static def createXLSXFile(List<String> headers = [], List items = [], OutputStream outputStream) {
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet();
int rowcount = 0;
// add header row
if (headers) {
Row row = sheet.createRow((short) rowcount++);
headers.eachWithIndex { String entry, int i ->
row.createCell(i).setCellValue(entry)
}
}
// add cells
items?.each { List entry ->
Row row = sheet.createRow((short) rowcount++);
entry.eachWithIndex { def value, int i -> row.createCell(i).setCellValue(value as String) }
}
wb.write(outputStream);
}
}
我的 Controller 使用 APIReport 对象进行响应
respond(report)
这似乎会产生一个损坏的文件,但是当我在 Controller 中以相同的方式执行相同的操作时:
withFormat {
xlsx {
def items = output.getItems()
def fields = output.getFields()
response.setHeader("Content-Type", "application/vnd.ms-excel")
response.setHeader("Content-disposition", "attachment; filename=\"${filename}.${params.format}\"")
def headers = (fields.keySet() + items[0].keySet()) as List
// convert maps to list of values each in order of the headers
def values = (items?:[]).collect { headers.collect { String h -> it?.containsKey(h) ? it[h] : output[h] } }
createXLSXFile(headers, values, response.outputStream)
return
}
}
效果很好。
APIReport类如下:
class APIReport extends AbstractMap<String, Object> {
// request call
ApiParameters apicall;
// response
Map<String, Object> fields;
Long itemCount;
List<Map<String, Object>> items;
Map<String, Object> summary;
}
我在渲染器中做错了什么吗?或者在 grails 2.3.8 中制作自定义渲染器的首选方法是什么
最佳答案
不要使用用于字符数据的 WriterOutputStream,而是使用 BufferedOutputStream 等二进制流将数据写入浏览器
关于java - 如何为 grails 编写 XLSX 自定义渲染器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24271300/