该文本主要描述了在一个没有内置插件的环境下,如何自定义实现数据导出功能,包括引出时修改数据样式、组合多个单据数据导出、设置单元格样式等需求。提出了通过XSSFWorkbook类来实现Excel样式的自定义,并详细描述了实现步骤,包括创建Java插件、在单据列表工具栏添加按钮、编写插件代码等。插件代码部分涵盖了从获取已选数据、构造XSSFWorkbook工作簿、写入数据到单元格、设置样式、构造输出流、转换输入流、上传到文件服务器的整个流程。特别指出了使用QueryServiceHelper查询其他单据数据的方法,以及如何通过XSSFWorkbook的API来设置单元格的高度、背景色、文字字体、颜色、字号等样式。最后,还展示了具体实现过程中的代码片段,包括如何获取数据、构造工作簿和单元格、数据填充、输出流处理等关键步骤。
关键词:引出,单据列表
一、需求
引出没有插件,只有引入有插件。
在引出时可能需要修改一些列头的样式风格,在引出时做一些对引出数据的修改。
我们需要一个更加自由地,自定义程度更高的方式去引出数据,并且在引出数据时,还能做到多个单据数据组合来引出。
在案例中,我并没有获取其他单据标识对应的单据的数据,但是理论上是可以实现:引出时,引出不同单据标识的数据。
只需要使用QueryServiceHelper查询其他单据标识,再按照上面的实现思路去导出数据。
单元格高度,单元格背景色,文字字体/颜色/字号 等等风格的定义,这些风格样式都可以通过XSSFWorkbook来实现,关于工作簿XSSFWorkbook类的一些具体用法,请各位开发者自行搜索。
二、思路与方案
实现思路是:
获取选择的列表数据,然后构造工作簿,使用工作簿生成输出流,再转成输入流,最后用调用文件服务,把输入流上传到文件服务器。
1. 创建java插件
2. 单据列表工具栏添加按钮,添加单据体列表插件
3. 编写java插件,分为几步:
3.1 获取已选数据,构造查询字段,QueryServiceHelper查询获取数据
3.2 构造XSSFWorkbook,构造行XSSFRow,构造单元格XSSFCell
3.3 把选择的数据填入XSSFWorkbook里面的单元格XSSFCell
3.4 构造OutputStream实例,把XSSFWorkbook写入OutputStream
3.5 OutputStream转为InputStream
3.6 创建文件路径,文件名,调用FileService的upload,把InputStream上传到文件服务器
3.7 弹出下载链接弹框
三、实现过程
1.新建单据列表插件
2.单据列表设计器
注册插件
添加按钮
3.编写插件
3.1获取已选数据,构造查询字段,QueryServiceHelper查询获取数据
/** * @param entityName 单据标识 * @param listColumns 列 * @param selectedRows 已选行 * @return */ private DynamicObjectCollection queryData(String entityName, List<IListColumn> listColumns, ListSelectedRowCollection selectedRows) { StringBuilder stringBuilder = new StringBuilder(); // 构造查询字段 for (int i = 0; i < listColumns.size(); i++) { IListColumn listColumn = listColumns.get(i); if (!listColumn.getListFieldKey().equals("fseq")) { if (i == listColumns.size() - 1) { stringBuilder.append(getFieldKey(entityName, listColumn)); } else { stringBuilder.append(getFieldKey(entityName, listColumn) + ", "); } } } String selectFields = stringBuilder.toString(); // 构造idList,获取已选行的id,之后作为过滤条件去查询数据 List<Long> idList = new ArrayList<>(); for (ListSelectedRow row : selectedRows) { idList.add((Long) row.getPrimaryKeyValue()); } // QFilter的过滤条件为:单据id等于idList里面的这些id才符合获取条件,其他的数据不获取 QFilter qFilter = new QFilter("id", QFilter.in, idList); // 查询数据 DynamicObjectCollection dynamicObjectCollection = QueryServiceHelper.query(entityName, selectFields, qFilter.toArray()); /*DynamicObject[] dynamicObjectArray = BusinessDataServiceHelper.load(entityName, selectFields, qFilter.toArray());*/ return dynamicObjectCollection; }
3.2构造XSSFWorkbook,构造行XSSFRow,构造单元格XSSFCell
合并第一行为标题
// 创建标题 XSSFRow headRow = sheet.createRow(0); XSSFCell headCell = headRow.createCell(0); headCell.setCellValue(title); XSSFCellStyle setBorder = workbook.createCellStyle(); setBorder.setFillForegroundColor(new XSSFColor(Color.RED));// 设置背景色 headCell.setCellStyle(setBorder); // 合并第1行的前几列,合并列数 = excel的列数 CellRangeAddress titleCellAddresses = new CellRangeAddress(0, 0, 0, excel.get(0).size() - 1); sheet.addMergedRegion(titleCellAddresses);
构造XSSFCell
//写入数据 for (int i = 0; i < excel.size(); i++) { XSSFRow nrow = sheet.createRow(i + 1); for (int u = 0; u < excel.get(i).size(); u++) { XSSFCell ncell = nrow.createCell(u); ncell.setCellValue(excel.get(i).get(u)); } }
3.3把选择的数据填入XSSFWorkbook里面的单元格XSSFCell,设置风格样式
/** * excel生成 * @param excel 数据源,List<List<String>>,外层的list是行,里面的List<String>是列,存储value * excel.size()是行数,excel.get(n).size()是列数 * @return */ private XSSFWorkbook excel(List<List<String>> excel, String title) { //创建excel工作簿 XSSFWorkbook workbook = new XSSFWorkbook(); //创建工作表sheet XSSFSheet sheet = workbook.createSheet(); //设置默认列宽 sheet.setDefaultColumnWidth(20); // 创建标题 XSSFRow headRow = sheet.createRow(0); XSSFCell headCell = headRow.createCell(0); headCell.setCellValue(title); // 设置首行标题的一些风格样式 XSSFCellStyle titleStyle = workbook.createCellStyle(); // 设置背景色 //设置填充方案 titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 正红色 //setBorder.setFillForegroundColor(new XSSFColor(Color.RED)); // 设置自定义填充颜色,天蓝色 titleStyle.setFillForegroundColor(new XSSFColor(new Color(135,206,250))); // 设置水平居中 titleStyle.setAlignment(HorizontalAlignment.CENTER); // 设置垂直居中 titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 设置字 XSSFFont font = workbook.createFont(); // 字体颜色橘红色 font.setColor(new XSSFColor(new Color(255 ,69,0))); // 设置字号 font.setFontHeight(20); // 设置字体 font.setFontName("微软雅黑"); titleStyle.setFont(font); headCell.setCellStyle(titleStyle); // 合并第1行的前几列,合并列数 = excel的列数 CellRangeAddress titleCellAddresses = new CellRangeAddress(0, 0, 0, excel.get(0).size()-1); sheet.addMergedRegion(titleCellAddresses); // 单据列表数据风格样式,设置字体为黑体,字号15 XSSFCellStyle billStyle = workbook.createCellStyle(); XSSFFont billFont = workbook.createFont(); billFont.setFontName("黑体"); billFont.setFontHeight(15); billStyle.setFont(billFont); //写入单据列表数据 for (int i = 0; i < excel.size(); i++) { // i+1是因为前面第1行加了一个标题,单据列表数据是从Excel的第2行开始的,所以要+1 XSSFRow nrow = sheet.createRow(i+1); for (int u=0;u<excel.get(i).size();u++){ XSSFCell ncell = nrow.createCell(u); ncell.setCellStyle(billStyle); ncell.setCellValue(excel.get(i).get(u)); } } return workbook; }
3.4构造OutputStream实例,把XSSFWorkbook写入OutputStream
OutputStream outputStream = new ByteArrayOutputStream(); workbook.write(outputStream);
3.5OutputStream转为InputStream
public ByteArrayInputStream parse(final OutputStream out) throws Exception { ByteArrayOutputStream baos = (ByteArrayOutputStream) out; final ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray()); return swapStream; }
3.6创建文件路径,文件名,调用FileService的upload,把InputStream上传到文件服务器
private String upload(String entityName, XSSFWorkbook workbook) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); String fileName = entityName + sdf.format(new Date()) + ".xlsx"; String pathName = "/offices/" + fileName; try { OutputStream outputStream = new ByteArrayOutputStream(); workbook.write(outputStream); InputStream inputStream = parse(outputStream); FileService fs = FileServiceFactory.getAttachmentFileService(); String path = fs.upload(new FileItem(fileName, pathName, inputStream)); return path; } catch (Exception e) { System.out.println(e.getMessage()); } return ""; }
3.7 弹出下载链接弹框
// 弹出提示框 getView().showMessage("下载文件链接:" + RequestContext.get().getClientFullContextPath() + "/attachment/download.do?path=" + path);
3.8 如果需要直接下载链接,可以用openUrl方法,在浏览器中打开新页签,访问下载链接。
这样浏览器就会直接下载这个excel文件。
getView().openUrl(RequestContext.get().getClientFullContextPath() + "/attachment/download.do?path=" + path)
四、效果图
打开Excel文件,效果如下,
五、开发环境版本
六、注意事项
异常场景
(1)在上传时,遇到了抛异常的场景,文件服务拒接连接。
可以从以下方向排查问题:
文件服务的磁盘容量是否超出上限,尝试删除上传路径的部分文件,看看能否解决问题。
文件服务是否在运行,尝试重启文件服务。
服务端和客户端的端口号是否正确,默认是8100。
七、参考资料
八、附件
附件包含补丁包和java源代码。
补丁包包含jar包和元数据包,请在mc中安装补丁包。
附件里的案例和本文的一些截图,在界面上略有差异,但实现方式是一致的。
插件代码: FruitOutPutListPlugIn.java,已上传至附件.
单据列表,插件引出Excel,弹出下载链接.zip(24.57KB)
推荐阅读