openApi开放接口-文件下载接口解密失败问题

OpenApi调开放文件下载接口解密失败问题

事情起因

首先由于本人在做项目时要用到openApi调开放接口进行数据同步,刚开始用的时候觉得挺舒服的,无非就是设置uuid和version字段判断同步的问题…

如果对openaApi不了解怎么使用可以参考这个Gitee仓库

地址:OpenApi的详细用法

开始

由于项目需求我们项目需要使用openApi进行开放接口的调用,机构端(SpringBoot框架项目),人行端(SpringCloudAlibaba框架项目)

人行端定义文件下载开放接口

image.png

代码如下 这里文件下载推荐把响应类型设置为FileBinary,方便后续对文件下载开放接口调用的加密解密(通过byte[]数组存储数据再转成文件)

/**
 * Create with IntelliT IDEA
 *
 * @Author: zhengmingzhe
 * @Date: 2022/08/11/9:12
 * @Description:  文件报送开放接口
 */
@Slf4j
@OpenApi("docReportOpenApi")
public class DocReportOpenApi {
//    @Autowired
//    private SysClient sysClient;
//
//    @Autowired
//    private OpenApiUtil openApiUtil;

    @Autowired
    private DocReportBusiness docReportBusiness;
    
    
  @OpenApiDoc(cnName = "文件报送-文件下载", retCnName = "文件")
    @OpenApiMethod("downloadFile")
    public FileBinary downloadFile(@OpenApiDoc(cnName = "文件表id数组") List<Long> fileIds){
         return docReportBusiness.downloadFile(fileIds);
    }
}



下载接口业务层代码(包括人行端和机构端的下载注意仔细对比)

  /*
     * @Description  机构端调用的文件下载
     * @Param
     * @return
     **/
    @SneakyThrows
    public FileBinary downloadFile(List<Long> fileIds) {
        FileBinary fileBinary = new FileBinary();
        //获取所有附件
        Map<Long, List<DocumentFile>> fileMap = documentFileService.list(new QueryWrapper<DocumentFile>().in("id", fileIds)).stream().collect(Collectors.groupingBy(DocumentFile::getZdswjbsId));
        Response feignResponse = null;
        if (fileMap.size()!=0) {
            if (fileIds.size() == 1) {//单文件下载
                Set<Long> keySet = fileMap.keySet();
                List<DocumentFile> fileList =new ArrayList<>();
                keySet.forEach(key->fileList.add( fileMap.get(key).get(0)));
                List<String> objectNames = fileList.stream().map(DocumentFile::getFileUrl).collect(Collectors.toList());
                Download download = new Download();
                download.setObjectNames(objectNames);
                feignResponse = minioClient.downloadMulti("", objectNames);
            } else {//多文件下载
                Map<String, List<String>> objectNameGroup = new HashMap<>();
                Set<Long> keySet = fileMap.keySet();
                keySet.forEach(key -> objectNameGroup.put(key + "", fileMap.get(key).stream().map(DocumentFile::getFileUrl).collect(Collectors.toList())));
                Download download = new Download();
                download.setObjectNameGroup(objectNameGroup);
                feignResponse = minioClient.downloadMultiGroup(download);
            }
        }
        InputStream is = null;
        try {
            is = feignResponse.body().asInputStream();
            if (is != null) {
                byte[] bytes1 = IOUtils.toByteArray(is);
                fileBinary.setData(bytes1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(is);
            return fileBinary;
        }
    }
    /*
     * @Description   人行端文件下载
     * @Param
     * @return
     **/
    @SneakyThrows
    public FileBinary download(List<Long> fileIds) {
        FileBinary fileBinary = new FileBinary();
        //获取所有附件
        Map<Long, List<DocumentFile>> fileMap = documentFileService.list(new QueryWrapper<DocumentFile>().in("id", fileIds)).stream().collect(Collectors.groupingBy(DocumentFile::getZdswjbsId));
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        Response feignResponse = null;
        if (fileMap.size()!=0) {
            if (fileIds.size() == 1) {//单文件下载
                Set<Long> keySet = fileMap.keySet();
                List<DocumentFile> fileList =new ArrayList<>();
                keySet.forEach(key->fileList.add( fileMap.get(key).get(0)));
                List<String> objectNames = fileList.stream().map(DocumentFile::getFileUrl).collect(Collectors.toList());
                Download download = new Download();
                download.setObjectNames(objectNames);
                feignResponse = minioClient.downloadMulti("", objectNames);
            } else {//多文件下载
                Map<String, List<String>> objectNameGroup = new HashMap<>();
                Set<Long> keySet = fileMap.keySet();
                keySet.forEach(key -> objectNameGroup.put(key + "", fileMap.get(key).stream().map(DocumentFile::getFileUrl).collect(Collectors.toList())));
                Download download = new Download();
                download.setObjectNameGroup(objectNameGroup);
                feignResponse = minioClient.downloadMultiGroup(download);
            }
        }
        InputStream is = null;
        try {
            is = feignResponse.body().asInputStream();
            if (is != null) {
                response.setCharacterEncoding("UTF-8");
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(new Date().getTime() + ".zip", "utf-8"));
                IOUtils.copy(is, response.getOutputStream());
                byte[] bytes1 = IOUtils.toByteArray(is);
                fileBinary.setData(bytes1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(is);
            return fileBinary;
        }
    }

好了就在这里 一致困扰我的加密解密问题出现了,由于我之前准备通用人行端机构端调用人行端这两个文件下载的业务代码,我就加上了这四行代码用来响应下载文件

image.png

image.png

罪魁祸首

但是正是因为这四行代码就让我的FileBinary里面封装的字节流byte[]数据直接被这个响应拦截了。。。就是说人行端调用这个文件下载的业务代码可以正常下载,但是机构端通过开放接口调用就会报openApi的解密错误

机构端调用人行端开放下载接口

以下是机构端调用人行端开放接口的客户端代码


/**
 * Create with IntelliT IDEA
 *
 * @Author: zhengmingzhe
 * @Date: 2022/08/11/10:42
 * @Description:  文件报送API客户端
 */
@OpenApiRef("docReportOpenApi")
@Component
public interface DocReportApiClient {
    /**
     * 上传报表文件
     *
     * @param fileBinary 文件
     */
    @OpenApiMethod(value = "upload", httpReadTimeout = 60)
    Outcome upload(FileBinary fileBinary);

    /*
     * @Description  文件信息保存同步
     * @Param
     * @return
     **/
    @OpenApiMethod(value = "saveFile", httpReadTimeout = 60)
    Outcome saveFile(DocumentSubEntity newReport);

    /*
     * @Description  根据uuid获取文件报送表集合
     * @Param        文件报送表uuid
     * @return
     **/
    @OpenApiMethod(value = "selectListByUuid", httpReadTimeout = 60)
    List<DocumentSubEntity> selectListByUuid(String uuid);

    /*
     * @Description   文件下载
     * @Param   文件表Id集合
     * @return
     **/
    @OpenApiMethod(value = "downloadFile", httpReadTimeout = 60)
    FileBinary downloadFile(List<Long> fileIds);
}

欧克,最后就是机构端调用客户端的文件下载接口(此接口是人行端定义的开放接口,实际业务逻辑代码都在人行端实现)



/**
 * Create with IntelliT IDEA
 *
 * @Author: zhengmingzhe
 * @Date: 2022/08/11/10:46
 * @Description:   文件报送接口(新)
 */
@Slf4j
@Api(tags = "文件报送接口-新")
@RestController
@RequestMapping("/docReport")
public class DocReportApi {
    @Autowired
    DocReportBusiness docReportBusiness;
    @Autowired
    DocumentFileService documentFileService;
    @Autowired
    DocumentSubService documentSubService;
    @Autowired
    DocumentFileLogService documentFileLogService;
    @Autowired
    SysUserBusiness sysUserBusiness;
    @Autowired
    DocReportApiClient docReportApiClient;

    @ApiOperation(value = "文件报送上传")
    @PostMapping("/upload")
    public Outcome upload(@RequestParam("file") MultipartFile file) {
        return docReportBusiness.upload(file);
    }


    @ApiOperation(value = "文件报送保存")
    @PostMapping("/saveDocmentSub")
    public Outcome saveItemReport(@RequestBody @Valid DocumentSubEntity documentSubEntity) {
        try {
            return docReportBusiness.saveItemReport(documentSubEntity);
        } catch (Exception ex) {
            log.error(ex.toString(), ex);
            return Outcome.failure("数据保存失败!");
        }
    }

    @ApiOperation("测试定时同步")
    @GetMapping("/doc")
    public Outcome syncDocReport() {
        try {
            return Outcome.success(docReportBusiness.syncDocReport());
        } catch (Exception ex) {
            log.error(ex.toString(), ex);
            return Outcome.failure("文件报送数据获取失败!");
        }
    }

    @ApiOperation("下载附件")
    @GetMapping(value = "/download")
    public void downloadFile( @RequestParam("fileIds") List<Long> fileIds,@RequestParam("filePath") String filePath) throws Exception {
        FileBinary fileBinary = docReportApiClient.downloadFile(fileIds);
        String fileName = "报送文件";
        byte[] bytes = fileBinary.getData();
        saveFile( fileName+".zip",bytes,filePath);
    }

    public static void saveFile(String filename, byte[] data,String filePath) throws Exception {
        if (data != null) {
//            String filepath = "D:\\" + filename;
            String filepath = filePath + filename;
            File file = new File(filepath);
            if (file.exists()) {
                file.delete();
            }
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(data, 0, data.length);
            fos.flush();
            fos.close();
        }
    }

}

上面是采用了FileBinary封装存储了字节流数组byte[]数据,然后再把字节流数据转成文件到指定文件夹下载

结语:

其实所谓的文件下载也逃不脱就是对数据的处理 ,但是如果涉及到加密解密,就得注意字节流数据的转换

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
org.springdoc.openapi-gradle-plugin 是一个基于 Gradle 构建工具的插件,用于为基于 Spring 框架的应用程序生成 OpenAPI 文档。通过使用这个插件,开发人员可以方便地将其 Spring Boot 项目转换为遵循 OpenAPI(以前称为 Swagger)规范的文档,并将它们发布到其应用程序的端点上。 该插件简化了将 OpenAPI 规范集成到 Spring Boot 项目中的流程,使开发人员可以轻松地生成、编译和定制 OpenAPI 文档。它还支持自动注解的映射,从而减少了手动配置的工作量。 org.springdoc.openapi-gradle-plugin 提供了一个易于使用的DSL(领域专用语言),让开发人员可以通过 Gradle 构建文件来自定义其生成的 OpenAPI 文档。通过配置插件,开发人员可以定义文档的标题、版本、描述、联系人信息、许可证等内容,还可以选择要包含在文档中的响应码、路径、参数等信息。 使用该插件,开发人员可以更方便地将其 Spring Boot 项目的 API 文档集成到其应用程序中。它还提供了丰富的扩展性和自定义选项,使开发人员能够根据其特定的需求进行定制。 总的来说,org.springdoc.openapi-gradle-plugin 是一个非常有用的工具,可以帮助开发人员将 OpenAPI 规范集成到他们的 Spring Boot 项目中,并生成易于阅读和理解的 API 文档。它简化了这一过程,并提供了丰富的定制选项,让开发人员可以根据其需求对文档进行个性化定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厌世小晨宇yu.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值