1.前言

HZERO的报表服务使用可以参考官方文档: http://hzerodoc.saas.hand-china.com/zh/docs/service/report/

这里仅介绍中文乱码及字符缺失问题解决方案。

官网提供了相关中文乱码解决方案

在这里插入图片描述

但是实践证明,这种方式有个缺陷:

①只能解决中文乱码问题,不能解决字符缺失问题。

②需要下载字体放置到服务器。如果使用K8S部署,还要将字体路径映射到容器内部,繁琐。

2.解决方案

1.思路

通过HZERO报表生成word,不会发生中文乱码及字符缺失问题。这种问题发生在报表PDF中。所以考虑先报表生成WORD,再将其通过aspose-words-15.8.0-jdk16.jar转换成PDF。这种放在使用window、linux、Mac

2.引入依赖

链接:http://pan.hand-china.com/owncloud/index.php/s/k9G9aLJlHFOgzF4

密码:123456

如图,将jar包放置在本地

在这里插入图片描述

引入依赖

<!--WORD转PDF-->
        <dependency>
            <groupId>com.aspose</groupId>
            <artifactId>aspose-words</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/extraJar/aspose-words-15.8.0-jdk16.jar</systemPath>
        </dependency>

3.开发

bjja.hzero.customs.api.controller.v1.PdfReportController

package bjja.hzero.customs.api.controller.v1;

import bjja.hzero.customs.app.service.PdfReportService;
import io.choerodon.core.iam.ResourceLevel;
import io.choerodon.swagger.annotation.Permission;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;

/**
 * @author pgc
 * @date 2020/6/9 17:17
 */
@Api(
        tags = {"PDF REPORT"}
)
@Controller("pdfReportController.v1")
@RequestMapping({"/v1/{organizationId}/pdfReport"})
public class PdfReportController {
    @Autowired
    private PdfReportService pdfReportService;

    @ApiOperation("导出新版PDF")
    @Permission(
            level = ResourceLevel.ORGANIZATION,
            permissionLogin = true
    )
    @GetMapping({"/word2pdf/{reportUuid}/{outputType}"})
    public void genPDFReport(
            @PathVariable("reportUuid") String reportUuid,
            @PathVariable("outputType") String outputType,
            @RequestParam String fileName,
            HttpServletRequest request,
            HttpServletResponse response
    ) throws FileNotFoundException {
        pdfReportService.genPDFReport(fileName, reportUuid, outputType, request, response);
    }
}

bjja.hzero.customs.app.service.impl.PdfReportServiceImpl

package bjja.hzero.customs.app.service.impl;

import bjja.hzero.customs.app.service.PdfReportService;
import bjja.hzero.customs.feign.ReportRomoteService;
import bjja.hzero.customs.util.DownLoadUtil;
import bjja.sys.platform.customs.infra.mapper.HsCodeMapper;
import cn.pigicutils.core.convert.Convert;
import cn.pigicutils.core.exceptions.UtilException;
import cn.pigicutils.core.io.FileUtil;
import cn.pigicutils.core.io.IORuntimeException;
import cn.pigicutils.core.io.IoUtil;
import cn.pigicutils.core.lang.Assert;
import cn.pigicutils.core.util.StrUtil;
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import lombok.SneakyThrows;
import org.hzero.core.base.BaseConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

/**
 * @author pgc
 * @date 2020/6/9 17:25
 */
@Service
public class PdfReportServiceImpl implements PdfReportService {
    @Autowired
    private ReportRomoteService reportRomoteService;
    @Autowired
    private HsCodeMapper hsCodeMapper;

    @Override
    @SneakyThrows
    public void genPDFReport(String fileName, String reportUuid, String outputType, HttpServletRequest request, HttpServletResponse response) {
        String code = hsCodeMapper.selectCodeByReportId(reportUuid);
        String headId = request.getParameter("headId");
        DownLoadUtil.configDownload(response, StrUtil.concat(true, fileName, ".pdf"));
        ServletOutputStream outputStream = response.getOutputStream();
        Assert.notBlank(headId, "headId不能为空");
        Long aLong = Convert.convert(Long.class, headId);
        byte[] reportFile = reportRomoteService.getReportFile(BaseConstants.DEFAULT_TENANT_ID,
                reportUuid,
                outputType,
                aLong,
                code,
                "zh_CN"
        );
        File fileParent = new File("/tmp");
        if (!fileParent.exists()) {
            fileParent.mkdirs();
        }
        File file = new File(fileParent, "/temp.docx");
        if (file.exists()) {
            file.delete();
        }
        File newfile = new File(fileParent, "/temp.docx");
        File file1 = FileUtil.writeBytes(reportFile, newfile);
        InputStream inputStream = new FileInputStream(file1);
        try {
            File file2 = genPDFwithWord(inputStream, "/tmp/tmp.pdf");
            FileInputStream fileInputStream = new FileInputStream(file2);
            try {
                IoUtil.copy(fileInputStream, outputStream);
            } catch (IORuntimeException e) {
                e.printStackTrace();
            } finally {
                fileInputStream.close();
            }
        } catch (IORuntimeException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            inputStream.close();
        }
    }

    /**
     * WORD转PDF
     *
     * @param wordStream
     * @param pdfPath
     */
    @SneakyThrows
    private File genPDFwithWord(InputStream wordStream, String pdfPath) {
        // 验证License 若不验证则转化出的pdf文档会有水印产生
        if (!getLicense()) {
            throw new UtilException("证书校验不通过!");
        }
        // 新建一个空白pdf文档
        File file = new File(pdfPath);
        FileOutputStream os = new FileOutputStream(file);
        // Address是将要被转化的word文档
        Document doc = new Document(wordStream);
        // 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF,
        doc.save(os, SaveFormat.PDF);
        return file;
    }

    /**
     * 获取证书,防止水印
     *
     * @return
     */
    private boolean getLicense() {
        boolean result = false;
        try {
            InputStream resourceAsStream = this.getClass().getResourceAsStream("/license.xml");
            License aposeLic = new License();
            aposeLic.setLicense(resourceAsStream);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

bjja.hzero.customs.util.DownLoadUtil

package bjja.hzero.customs.util;

import cn.pigicutils.core.exceptions.UtilException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @Author: 潘顾昌
 * @Date: 2019/9/24 11:26
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DownLoadUtil {

    public static HttpServletResponse configDownload(HttpServletResponse response, String fileName) {
        // 配置文件下载
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        // 下载文件能正常显示中文
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new UtilException("转换出错!");
        }
        return response;
    }
}

去除水印的license.xml下载,放在项目resources文件夹下

链接:http://pan.hand-china.com/owncloud/index.php/s/nwouW5UTiwdVwH5
密码:123456

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐