关键词:OpenApi2.0案例,开放平台,导出
一、需求
通过调用苍穹api的方式,获取到一个excel文件,excel里面存放了单据数据。
二、思路与方案
思路:
构建出excel表格,需要有数据源,我们可以使用QueryServiceHelper,将多个DataSet使用Algo合并为一个数据源。
构建出excel表格,可以使用POI框架(苍穹的jar包带了POI框架,无需二次引入),构造XSSFWorkbook对象来生成excel。
有了excel表格之后,将它转为文件流,上传到我们的文件服务器上。上传时可以指定文件路径。有了文件路径之后,我们就可以拼接为一个下载路径。
以上业务逻辑,可以使用openapi2.0,在自定义服务插件中实现。当用户调用api时,将下载路径响应给用户。
方案:
1.进入开放平台,创建第三方app
2.编写自定义服务插件:
2.1在插件中获取单据数据,生成excel文件对象
2.2调用文件服务,生成下载链接
3.创建api2.0的自定义服务
4.使用http工具,调用自定义服务,测试api接口:
4.1调用第三方app服务,获取apptoken
4.2调用/login.do,获取accesstoken
4.3调用自定义服务,获取文件下载链接
三、实现过程
准备数据源
这一步是本案例的准备工作,我们接下来将要把以下单据列表数据导出到excel表格中。
如果各位读者已有需要导出的数据源,当前步骤可以跳过。
创建 基础资料“化肥”,单据“水果”,添加预置数据,为即将导出的数据准备数据源。
页面结构请参考我的上一篇文章:
如何通过二开的方式将数据导出到Excel,并调整Excel样式
添加预置数据如下:
创建第三方app
开发服务云,进入开放平台,进入第三方应用列表,新增一个第三方应用。
认证方式选择最基本的accessToken;
api授权勾选“全部api授权”(这里仅作为演示,实际场景建议配置授权api)。
编写自定义服务插件
(1)创建自定义服务类FruitApi2Plugin,添加@ApiController @ApiMapping注解;
(2)添加exportFruitPro方法,添加@ApiPostMapping注解;
(3)方法入参numberFilter,添加@ApiParam注解;
(4)响应模型FruitModel类,添加@ApiResponseBody注解。
@ApiController(value = "kdec_wrx_col_app", desc = "导出水果生产数据") @ApiMapping("/fp") public class FruitApi2Plugin { @Validated @ApiPostMapping("/export") public CustomApiResult<@ApiResponseBody("响应") FruitModel> exportFruitPro(@Valid @NotNull @ApiParam(value = "过滤") String numberFilter) { String title = "水果生产以及产地"; DataSet dataSet = queryData(numberFilter); List<List<String>> excelList = getExcelList(dataSet); // 创建excel工作簿 XSSFWorkbook workbook = MyExportUtil.excel(excelList, title); // 上传 String path = MyExportUtil.upload(title, workbook); String downloadUrl = RequestContext.get().getClientFullContextPath() + "/attachment/download.do?path=" + path; FruitModel fruitModel = new FruitModel(); fruitModel.setUrl(downloadUrl); return CustomApiResult.success(fruitModel); } }
(5)创建FruitModel类,添加@ApiModel注解,实例化Serializable接口;
内部变量url,添加@ApiParam注解,之后会把这个变量存储excel文件的下载链接。
@ApiModel public class FruitModel implements java.io.Serializable{ @ApiParam(value = "下载链接", position = 1) String url; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
(6)查询数据
public DataSet queryData() { DataSet dataSetFruits = QueryServiceHelper.queryDataSet("FruitPro", "kdec_fruit_bill", "id, billno as kdec_fnumber, kdec_entryentity.kdec_fruits as kdec_fname, kdec_fruit_pro.id as proid, kdec_fruit_pro.name as kdec_pro", null, ""); DataSet dataSet2 = dataSetFruits.copy(); Iterator<Row> iterator = dataSet2.iterator(); List proList = new ArrayList<>(); while (iterator.hasNext()) { Row row = iterator.next(); proList.add(row.get("proid")); } QFilter qFilter = new QFilter("kdec_region", QCP.in, proList); DataSet dataSetFertilizer = QueryServiceHelper.queryDataSet("FruitPro", "kdec_fertilizer_bill", "id, billno as kdec_fernumber, kdec_name as kdec_fername, kdec_region", qFilter.toArray(), ""); DataSet result = dataSetFruits.rightJoin(dataSetFertilizer) .select(new String[]{"kdec_fnumber", "kdec_fname", "kdec_pro"}, new String[]{"kdec_fernumber", "kdec_fername"}) .on("proid", "kdec_region").finish(); return result; }
(7)构造准备导出的excel数据源
public List<List<String>> getExcelList (DataSet dataSet) { // excelList用于提供数据源给 excel工作簿,外层的list是行,里面的List<String>是列,存储value List<List<String>> excelList = new ArrayList<>(); List<String> titles = new ArrayList<>(); titles.add("水果编码"); titles.add("水果名称"); titles.add("产地"); titles.add("化肥编码"); titles.add("化肥名称"); excelList.add(titles); while (dataSet.hasNext()) { Row row = dataSet.next(); List<String> strings = new ArrayList<>(); for ( int j = 0; j < row.size(); j++) { String value = row.getString(j); strings.add(value); } excelList.add(strings); } return excelList; }
(8)构造XSSFWorkbook对象,此处省略了部分风格样式设置的代码,如果有需要,请查看源码
public static XSSFWorkbook excel(List<List<String>> excelList, String title) { //创建excel工作簿 XSSFWorkbook workbook = new XSSFWorkbook(); //创建工作表sheet XSSFSheet sheet = workbook.createSheet(); //写入单据列表数据 for (int i = 0; i < excelList.size(); i++) { // i+1是因为前面第1行加了一个标题,单据列表数据是从Excel的第2行开始的,所以要+1 XSSFRow nrow = sheet.createRow(i+1); for (int u=0;u<excelList.get(i).size();u++){ XSSFCell ncell = nrow.createCell(u); if (i == 0) { ncell.setCellStyle(firstRowStyle); } else if (u == 0) { ncell.setCellStyle(firstColumnStyle); } else { ncell.setCellStyle(billStyle); } ncell.setCellValue(excelList.get(i).get(u)); } } return workbook; }
(9)将XSSFWorkbook转为文件流,并调用FileService上传
public static 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 ""; }
创建api
进入api管理列表,选择一个业务云,选择云下面的应用(业务云和应用在开发平台中创建)。
如上图点击新增之后,选择“自定义API”
把上一步写好的api2.0的类和路径输入,点击“同步”按钮,会按照注解信息,把FruitApi2Plugin的信息加载到当前页面上
点击同步之后的效果
调用api服务
我使用postman工具,调用刚刚创建好的自定义api服务。
(1)调用第三方应用/api/getAppToken.do,获取app token
(2)使用app token,调用/api/login.do获取access token
(3)使用access token,调用自定义api服务。
注意access token是放在请求头里面的。
在请求体中,设置编码过滤。
最终响应体如图所示,返回了excel文件下载链接:
四、效果图
将excel文件下载链接,放到浏览器中访问:
最终下载文件如下:
五、开发环境版本
六、注意事项
开放平台的api2.0是比较新的苍穹版本中才能使用的,例如我的苍穹版本是5.0.008(参考上图)。
七、参考文章
自定义API(脚本开发)
https://vip.kingdee.com/link/s/MDlc2
金蝶云苍穹开放平台API调用流程
https://vip.kingdee.com/link/s/MDl7p
如何通过二开的方式将数据导出到Excel,并调整Excel样式
https://vip.kingdee.com/link/s/MIttZ
openapi导出.zip(34.32KB)
推荐阅读