本文概述了如何从苍穹平台下载指定业务单据及其所有附件到第三方系统的需求与实现方案。首先,由于苍穹平台未直接提供OpenAPI接口查询附件,开发了一个自定义服务接口来查询附件信息。接着,在第三方系统中获取访问苍穹OpenAPI接口的accessToken,封装参数调用自定义服务接口查询附件信息,然后根据存储地址获取文件流并持久化到第三方系统。最后,文章还提及了开发环境版本要求、注意事项、案例元数据和Java代码的使用方法,以及参考资料。
关键词:OpenAPI、附件面板
一、需求
苍穹平台内有一业务单据,其中存在多个附件面板控件。现有第三方系统,需从苍穹下载该单据中指定的业务数据及其所有附件,从而进行其他业务操作。
二、思路与方案
2.1 分析思路
苍穹平台中存在非常多的业务单据,且各业务单据上也可能存在多个附件面板去存放不同的附件文件,而各业务单据上各附件面板上附件的存储路径是互不相同的。所以,我们并不能通过某一个固定的地址去获取苍穹平台内的附件。但是平台底层每次在持久化附件面板中的文件时都会在表 T_BAS_ATTACHMENT(页面标识:bos_attachment)中存储与之相关的所有信息,包括附件文件在附件服务器上存储的相对路径。这样,我们就可考虑先通过一个自定义服务接口查询到附件信息,然后根据其中的附件存储文件获取到文件流,最后将流持久化到第三方系统即可。
2.2 实现方案
因平台对外暂未提供直接查询单据附件的OpenAPI接口,故针对该需求,我们可先开发一个自定义服务接口来实现查询指定业务单据上指定的附件信息,从而得到这些附件在苍穹附件服务器上的存储路径。然后,在第三方系统中遍历该自定义服务接口返回的附件信息,根据其中的附件存储路径获取其文件流,最后将文件流持久化到第三方系统中。
三、实现过程
1. 开发自定义服务,实现业务逻辑:根据条件(单据主键ID)查询苍穹平台中指定业务单据上指定附件的信息。
@Override public ApiResult doCustomService(Map<String, Object> params) { Map<String, Object> resultInfo = new HashMap<String, Object>(); // 参数信息 Map<String, Object> paramMap = (Map<String, Object>) params.get("params"); logger.info("参数: " + paramMap); Object entityNumber = paramMap.get("entityname"); Object pkId = paramMap.get("pkid"); if (StringUtils.isBlank(entityNumber) || StringUtils.isBlank(pkId)) { return ApiResult.fail("查询失败, 参数为空 !"); } Object attachKeyObj = paramMap.get("attachmentpanelkey"); List<String> attachKeyList = null; if (StringUtils.isNotBlank(attachKeyObj)) { attachKeyList = ((List<String>) attachKeyObj); } else { attachKeyList = new ArrayList<String>(); Map<String, String> attachmentMap = AttachmentServiceHelper.getAttachmentsForApi(entityNumber.toString(), pkId); Set<String> attachmentPannelKeys = attachmentMap.keySet(); attachKeyList.addAll(attachmentPannelKeys); } Object fileNamesObj = paramMap.get("filenames"); List<String> fileNameList = StringUtils.isNotBlank(fileNamesObj) ? (List<String>) fileNamesObj : null; // 单据上所有附件面板下的所有附件 Map<String, List<Map<String, Object>>> allAttachments = new HashMap<String, List<Map<String, Object>>>(); // 某个附件面板下所有的附件 List<Map<String, Object>> attachments = null; for (String tempAttaKey : attachKeyList) { attachments = AttachmentServiceHelper.getAttachments(entityNumber.toString(), pkId, tempAttaKey); Iterator<Map<String, Object>> iterator = attachments.iterator(); if (fileNameList != null && !fileNameList.isEmpty()) { Map<String, Object> tempAtta = null; while (iterator.hasNext()) { tempAtta = iterator.next(); for (String tempFileName : fileNameList) { if (!StringUtils.equalsIgnoreCase(tempFileName, tempAtta.get("name").toString())) { iterator.remove(); } } logger.info("查询到附件面板( " + tempAttaKey + " )下的附件 " + tempAtta.get("name")); } } if (attachments != null && !attachments.isEmpty()) { allAttachments.put(tempAttaKey, attachments); } } resultInfo.put("allattachments", allAttachments); return ApiResult.success(resultInfo); }
2. 在第三方系统中获取访问苍穹OpenAPI接口的accessToken。
public static void main(String[] args) { ThirdSysRemoteOperateAttachmentWithCosmic remoteOperateAtta = new ThirdSysRemoteOperateAttachmentWithCosmic(); // 获取appToken,需在方法体内修改配置信息 String appToken = AppLoginService.getService().getAppToken(URL_COSMICHOST); // 获取accessToken,需在方法体内修改配置信息 String accessToken = UserLoginService.getService().getAccessToken(URL_COSMICHOST, appToken); try { // 远程下载附件 remoteOperateAtta.remoteDownloadAttaFromCosmic(accessToken); } catch (Exception e) { e.printStackTrace(); } }
3. 在第三方系统中封装参数,调用第 1 步中开发的自定义服务接口查询苍穹平台中指定单据上的附件信息。
/** * 远程查询附件信息 * @param accessToken * @throws Exception */ @SuppressWarnings("unchecked") private Map<String, List<Map<String, Object>>> remoteGetAttasFromCosmic(String accessToken) throws Exception { String responseStr = null; Map<String, Object> params = this.getParameters(); // 查询附件信息 responseStr = BizOperateService.getService().bizGetAttachmentsInfo(URL_COSMICHOST, accessToken, params); JSONObject responseJson = JSONObject.parseObject(responseStr); Boolean success = (responseJson == null || responseJson.isEmpty()) ? false : Boolean.valueOf(responseJson.getString("success")); Map<String, List<Map<String, Object>>> allAttachments = null; if (success) { // 查询到的附件信息(key:附件面板标识符;value:该附件面板下附件集合) allAttachments = (Map<String, List<Map<String, Object>>>) responseJson.getJSONObject("data").get("allattachments"); } else { throw new Exception("远程查询附件信息失败!"); } return allAttachments; }
4. 在第三方系统中遍历第 3 步中查询到的附件信息,根据其中的附件存储地址获取其文件流,并将其持久化到第三方系统中。
/** * 远程下载附件 * @param accessToken * @throws Exception */ private void remoteDownloadAttaFromCosmic(String accessToken) throws Exception { // 下载指定附件 Map<String, List<Map<String, Object>>> allAttachments = this.remoteGetAttasFromCosmic(accessToken); // 遍历附件面板标识 for (String tempAttaKey : allAttachments.keySet()) { // 该附件面板下的所有附件 List<Map<String, Object>> attachments = allAttachments.get(tempAttaKey); for (Map<String, Object> tempAttachment : attachments) { String url = tempAttachment.get("url").toString(); System.out.println("url: " + url); InputStream is = null; // 创建默认http客户端 CloseableHttpClient httpClient = HttpClients.createDefault(); // 采用默认请求配置 RequestConfig requestConfig = RequestConfig.DEFAULT; // 通过get方法下载文件流 HttpGet request = new HttpGet(url); // 设置请头求配置 request.setConfig(requestConfig); try { // 执行请求,接收返回信息 CloseableHttpResponse httpResponse = httpClient.execute(request); // 获取执行状态 int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED) { request.abort(); } else { HttpEntity entity = httpResponse.getEntity(); if (null != entity) { // 获取返回内容 is = entity.getContent(); } } } catch (Exception e) { e.printStackTrace(); request.abort(); } // 本地存放位置 StringBuffer path = new StringBuffer(); path.append("E:\\测试下载远程文件\\").append(tempAttachment.get("name")); File file = new File(path.toString()); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } FileOutputStream fos = null; try { fos = new FileOutputStream(file); int bytes = 0; byte[] buffer = new byte[1024]; while ((bytes = is.read(buffer)) != -1) { fos.write(buffer, 0, bytes); } System.out.println("文件下载成功!"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { this.close(is); this.close(fos); } } } }
四、效果图
五、开发环境版本
V2.0.036(含)以上
六、注意事项
1. 如需复现样例效果,请注意按实际系统配置信息修改代码中相关变量参数。
2. 文章附件包含案例元数据补丁包、Java代码源码。解压之后请在MC中以更新补丁的形式将元数据压缩包导入平台里,Java代码放到本地开发工具(Eclipse/Idea)中,重启服务,运行代码即可查看效果,实际操作请查阅附件内的文档《操作步骤.doc》。
七、参考资料
复制合同模板(基础资料)上的附件并填充数据后重新绑定到业务单据上
第三方系统远程下载苍穹系统内指定单据的所有附件.zip(160.94KB)
推荐阅读