青柠部落阁青柠部落阁
Java
Git
Collect
Vue
Nginx
Others
GitHub
Java
Git
Collect
Vue
Nginx
Others
GitHub
  • Java

    • 在Windows平台替换Jar包的依赖
    • 实现FastJson中弃用的isValidArray和isValidObject
    • 博思发票下载
    • SpringBoot多线程处理任务列表

博思发票下载

一般情况博思会返回发票预览的网页,如果遇到需要下载发票PDF的场景可通过以下方法实现服务端下载

Maven依赖

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.24</version>
</dependency>

重定向链接(博思发票源链接需要重定向3次才会到最终页面)

@SneakyThrows
private String getRedirectUrl(String sourceUrl) {
    HttpURLConnection conn = null;
    try {
        URL url = new URL(sourceUrl);
        conn = (HttpURLConnection) url.openConnection();
        conn.setInstanceFollowRedirects(false);
        conn.connect();
        int responseCode = conn.getResponseCode();
        if (responseCode >= 300 && responseCode < 400) {
            String location = conn.getHeaderField("Location");
            if (location != null) {
                return location;
            }
        }
        return sourceUrl;
    } finally {
        if (conn != null) {
            conn.disconnect();
        }
    }
}

下载发票(eleBillUrl为电子票据查看地址,pdfPath为保存路径)


@Resource
private RestTemplate restTemplate;

@SneakyThrows
private void downloadAndConvertImageToPDF(String eleBillUrl, String pdfPath) {
    eleBillUrl = getRedirectUrl(getRedirectUrl(getRedirectUrl(eleBillUrl)));
    URI uri = new URI(eleBillUrl);
    String query = uri.getQuery();
    JSONObject queryParams = new JSONObject();
    if (query != null) {
        String[] pairs = query.split("&");
        for (String pair : pairs) {
            String[] keyValue = pair.split("=");
            if (keyValue.length == 2) {
                queryParams.put(keyValue[0], keyValue[1]);
            } else {
                queryParams.put(keyValue[0], "");
            }
        }
    }
    HttpHeaders headers = new HttpHeaders();
    headers.set("Content-Type", "application/x-www-form-urlencoded");
    MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
    params.add("order", queryParams.getString("order"));
    params.add("appId", queryParams.getString("appId"));
    params.add("invoiceType", queryParams.getString("invoiceType"));
    HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(params, headers);
    JSONObject result = restTemplate.postForEntity("https://www.chinaebill.cn/agency-public-service-h5/H5FinanceDisplay/getInvoiceInfo", httpEntity, JSONObject.class).getBody();
    if (null == result) {
        return;
    }
    URL url = new URL(result.getJSONObject("data").getJSONArray("displayInvoice").getJSONObject(0).getString("imgURL"));
    try (InputStream imageInputStream = new BufferedInputStream(url.openStream()); PDDocument document = new PDDocument()) {
        PDPage page = new PDPage();
        document.addPage(page);
        // 将输入流转换为字节数组
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[16384];
        while ((nRead = imageInputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }
        buffer.flush();
        byte[] imageBytes = buffer.toByteArray();
        float scale = Math.min(595f / 1077f, 842f / 720f);
        // 将字节数组转换为PDImageXObject
        PDImageXObject pdImage = PDImageXObject.createFromByteArray(document, imageBytes, "image");
        PDPageContentStream contentStream = new PDPageContentStream(document, page);
        contentStream.drawImage(pdImage, (595f - pdImage.getWidth() * scale) / 2, (842f - pdImage.getHeight() * scale) / 2, pdImage.getWidth() * scale, pdImage.getHeight() * scale);
        contentStream.close();
        document.save(pdfPath);
    }
}
Contributors: ChenYue
Prev
实现FastJson中弃用的isValidArray和isValidObject
Next
SpringBoot多线程处理任务列表