分享

SpringBoot+AngularJS+Jaspersoft Studio实现多张报表打印控制

 WindySky 2017-12-04

报表在JavaWeb中是个非常常用的技术,本文介绍使用SpringBoot+AngularJS+Jaspersoft Studio对报表打印进行实现
一.使用Jaspersoft Studio进行报表的绘制后,存放在src/main/resources/reports文件夹下。
二.实现多张报表生成后台代码详解
此方法应用了JasperReport和JRAbstractExporter包对报表进行无脑化编译。

     @RestController
     @RequestMapping(LevyDetailController.BASE_URL)
      public class LevyDetailController {

    public static Logger LOGGER = LoggerFactory.getLogger(LevyDetailController.class);

    /** 根路径 */
    public final static String BASE_URL = "/reports/levy";

    /** 报表打印服务接口类 */
    @Resource
    private LevyDetailService levyDetailService;

    @SuppressWarnings("unchecked")
    @RequestMapping(method = RequestMethod.GET)
    public void printReport(@RequestParam("format") String format, @RequestParam("companyId") Long companyId,
            @RequestParam(required = false) Long issue, @RequestParam(required = false) Long pageIndex,
            HttpServletRequest request, HttpServletResponse response) {
        String requestFullUri = request.getRequestURI() + "?" + request.getQueryString();
        OrganizationApplyService organizationApplyService = (OrganizationApplyService) SpringContextUtils
                .getApplicationContext().getBean("organizationApplyServiceImpl");
        OrganizationApply company = organizationApplyService.findByOrgId(companyId);
        // 获取报表数据
        CompanyLevyListDTO result = levyDetailService.getLevyDetail(company, issue);
        // result.setList(null);测试空报表
        // 打印控制获取上下文
        ApplicationContext ctx = SpringContextUtils.getApplicationContext();
        org.springframework.core.io.Resource resource = null;
        if (result.getList() == null) {
            // 生成空白报表
            resource = ctx.getResource("classpath:/reports/rptEmpty.jrxml");
        } else {
            resource = ctx.getResource("classpath:/reports/rptLevyDetailx.jrxml");
        }

        InputStream inputStream;
        try {
            // 译为输入流
            inputStream = resource.getInputStream();
            // 编译报表
            JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);
            JRAbstractExporter exporter = new JRPdfExporter();
            List<JasperPrint> list = new ArrayList<>();
            // 多张报表打印实现
            if (result.getList() != null) {
                for (CompanyLevyDTO dto : result.getList()) {
                    // 获取报表数据map源
                    JasperPrint jasperprint = JasperFillManager.fillReport(jasperReport,
                            LevyDetaiFactorySolitary.getReportData(format, requestFullUri, dto, issue,
                                    company.getName(), company.getCompanyNumber()),
                            LevyDetaiFactorySolitary.mapData(dto.getLevyBodyListDTO()));
                    list.add(jasperprint);
                }
            } else {
                JasperPrint jasperprint = JasperFillManager.fillReport(jasperReport,
                        (Map<String, Object>) DefaultEmptyFactory.getReportData(format, requestFullUri),
                        DefaultEmptyFactory.mapData());

                list.add(jasperprint);
            }
            // 设置前台编译格式
            ServletOutputStream baos = response.getOutputStream();
            exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, list);
            exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
            exporter.setParameter(JRExporterParameter.CHARACTER_ENCODING, "UTF-8");
            exporter.exportReport();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JRException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

三.单张报表生成后台代码详解
此方法使用最基本SpringBooot response传入字节数组方式生成报表,代码如下:

 @RestController
 @RequestMapping(LevyDetailController.BASE_URL)
 public class LevyDetailController {

public static Logger LOGGER = LoggerFactory.getLogger(LevyDetailController.class);

/** 根路径 */
public final static String BASE_URL = "/reports/levy";

/** 报表打印服务接口类 */
@Resource
private LevyDetailService levyDetailService;

@Autowired
private PileStamperClient pileStamperClient;

@RequestMapping(method = RequestMethod.GET)
public void printReport(@RequestParam("format") String format, @RequestParam("companyId") Long companyId,
        @RequestParam(required = false) Long issue, @RequestParam(required = false) Long pageIndex,
        HttpServletRequest request, HttpServletResponse response) throws JSONException {
    String requestFullUri = request.getRequestURI() + "?" + request.getQueryString();

    OrganizationApplyService organizationApplyService = (OrganizationApplyService) SpringContextUtils
            .getApplicationContext().getBean("organizationApplyServiceImpl");

    OrganizationApply company = organizationApplyService.findByOrgId(companyId);
    // 获取报表数据
    CompanyLevyListDTO result = levyDetailService.getLevyDetail(company, issue);
    // result.setList(null);测试空报表
    // 打印控制获取上下文
    ApplicationContext ctx = SpringContextUtils.getApplicationContext();
    org.springframework.core.io.Resource resource = null;
    if (result.getList() == null) {
        // 生成空白报表
        resource = ctx.getResource("classpath:/reports/rptEmpty.jrxml");
    } else {
        resource = ctx.getResource("classpath:/reports/rptLevyDetailx.jrxml");
    }

    InputStream inputStream;
    try {
        byte[] bytesPdf = null;
        // 译为输入流
        inputStream = resource.getInputStream();
        // 编译报表
        JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);

        // 单张报表打印实现
        if (result.getList() != null) {
            for (int t = 0; t < result.getList().size(); t++) {
                CompanyLevyDTO dto = result.getList().get(t);
                bytesPdf = JasperRunManager.runReportToPdf(jasperReport,
                        LevyDetaiFactorySolitary.getReportData(format, requestFullUri, dto, issue,
                                company.getName(), company.getCompanyNumber()),
                        LevyDetaiFactorySolitary.mapData(dto.getLevyBodyListDTO()));

            }
        } else {
            bytesPdf = JasperRunManager.runReportToPdf(jasperReport,
                    DefaultEmptyFactory.getReportData(format, requestFullUri), DefaultEmptyFactory.mapData());
        }

        ByteArrayInputStream stream = new ByteArrayInputStream(bytesPdf);
        int length = stream.available();
        if (length != -1) {
            byte[] buffer3 = new byte[1024];
            int readCount = 0;
            ServletOutputStream sos = response.getOutputStream();

            while ((readCount = stream.read(buffer3)) > 0) {
                sos.write(buffer3, 0, readCount);
            }
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (JRException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

五.使用PDFMergerUtility进行PDF字节流合成导出
mvn引入jar包

    <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox-app</artifactId>
            <version>1.8.13</version>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
@RestController
@RequestMapping(LevyDetailController.BASE_URL)
public class LevyDetailController {

    public static Logger LOGGER = LoggerFactory.getLogger(LevyDetailController.class);

    /** 根路径 */
    public final static String BASE_URL = "/reports/levy";

    /** 报表打印服务接口类 */
    @Resource
    private LevyDetailService levyDetailService;

    @RequestMapping(method = RequestMethod.GET)
    public void printReport(@RequestParam("format") String format, @RequestParam("companyId") Long companyId,
            @RequestParam(required = false) Long issue, @RequestParam(required = false) Long pageIndex,
            HttpServletRequest request, HttpServletResponse response) {
        String requestFullUri = request.getRequestURI() + "?" + request.getQueryString();
        OrganizationApplyService organizationApplyService = (OrganizationApplyService) SpringContextUtils
                .getApplicationContext().getBean("organizationApplyServiceImpl");
        OrganizationApply company = organizationApplyService.findByOrgId(companyId);
        // 获取报表数据
        CompanyLevyListDTO result = levyDetailService.getLevyDetail(company, issue);
        // result.setList(null);测试空报表
        // 打印控制获取上下文
        ApplicationContext ctx = SpringContextUtils.getApplicationContext();
        org.springframework.core.io.Resource resource = null;
        if (result.getList() == null) {
            // 生成空白报表
            resource = ctx.getResource("classpath:/reports/rptEmpty.jrxml");
        } else {
            resource = ctx.getResource("classpath:/reports/rptLevyDetailx.jrxml");
        }

        InputStream inputStream;
        try {
            byte[] bytesPdf = null;
            // 译为输入流
            inputStream = resource.getInputStream();
            // 编译报表
            JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);

            // 多张报表打印实现
            if (result.getList() != null) {
                List<byte[]> list = new ArrayList<byte[]>();
                for (CompanyLevyDTO dto : result.getList()) {
                    // 获取报表数据map源
                    bytesPdf = JasperRunManager.runReportToPdf(jasperReport,
                            LevyDetaiFactorySolitary.getReportData(format, requestFullUri, dto, issue,
                                    company.getName(), company.getCompanyNumber()),
                            LevyDetaiFactorySolitary.mapData(dto.getLevyBodyListDTO()));

                    list.add(bytesPdf);
                }
                if (result.getList().size() > 1) {
                    // 多张表单拼接实现
                    PDFMergerUtility mergePdf = new PDFMergerUtility();
                    for (int i = 0; i < list.size(); i++) {
                        byte[] content = list.get(i);
                        ByteArrayInputStream in = new ByteArrayInputStream(content);
                        mergePdf.addSource(in);
                    }
                    // 多个pdf流合成处理
                    mergePdf.setDestinationStream(new ByteArrayOutputStream());
                    try {
                        mergePdf.mergeDocuments();
                    } catch (COSVisitorException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    // 获取合成后的OutputStream流
                    ByteArrayOutputStream outputStream = (ByteArrayOutputStream) mergePdf.getDestinationStream();
                    bytesPdf = outputStream.toByteArray();
                }

            } else {
                bytesPdf = JasperRunManager.runReportToPdf(jasperReport,
                        DefaultEmptyFactory.getReportData(format, requestFullUri), DefaultEmptyFactory.mapData());
            }

            ByteArrayInputStream stream = new ByteArrayInputStream(bytesPdf);
            // 返回从输入流中读取的字节数,若无字节 返回0
            int length = stream.available();
            if (length != -1) {
                byte[] buffer3 = new byte[1024];
                int readCount = 0;
                ServletOutputStream sos = response.getOutputStream();

                while ((readCount = stream.read(buffer3)) > 0) {
                    // 从buffer3中读取0-readCount的数据
                    sos.write(buffer3, 0, readCount);
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JRException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104

四.LevyDetaiFactorySolitary实现,代码如下

public class LevyDetaiFactorySolitary {

    private LevyDetaiFactorySolitary() {

    }

    public static final String LEVY_REPORT_NAME = "rptLevyDetailx";
    public static final String LEVY_FULL_URI = "request_full_uri";

    public static String getReportName() {
        return LEVY_REPORT_NAME;
    }

    /**
     * 获取报表数据
     * 
     * @param format
     * @param requestFullUri
     * @param dto
     * @return
     */
    public static Map<String, Object> getReportData(String format, String requestFullUri, CompanyLevyDTO dto,
            Long issue, String name, String companyNumber) {

        Map<String, Object> model = new HashMap<String, Object>();
        model.put(JasperReportsMultiFormatView.DEFAULT_FORMAT_KEY, format);
        model.put(LEVY_FULL_URI, requestFullUri);
        model.put("name", "名称:" + name);
        ...//这里面放不是循环的参数
        return model;
    }

    /**
     * 获取报表DataSource数据
     * 
     * @param format
     * @param requestFullUri
     * @param dto
     * @return
     */
    public static JRMapCollectionDataSource mapData(List<LevyBodyDTO> list) {
        Collection<Map<String, ?>> collection = new ArrayList<Map<String, ?>>();
        for (int i = 0; i < list.size(); i++) {
            Map<String, Object> map = new HashMap<String, Object>();
            LevyBodyDTO dto = list.get(i);
            map.put("insuranceCode", dto.getInsuranceCode());
    ...//这里面放循环的数据
            collection.add(map);
        }

        return new JRMapCollectionDataSource(collection);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

五.也可以使用直接返回前台ModelAndView的形式进行实现
代码入下:

 ModelAndView module = null;
        if (listDimissionDTO.size() == 0) {
            // 生成报表
            module = new ModelAndView(DefaultEmptyFactory.getReportName(),
                    DefaultEmptyFactory.getReportData(format, requestFullUri));
        } else {
            // 生成报表
            module = new ModelAndView(LevyDetaiFactorySolitary .getReportName(),
                    LevyDetaiFactorySolitary .getReportData(reportPageIndex, format, requestFullUri, listDimissionDTO, issue,
                            company.getName(), company.getCompanyNumber(), reviewedStatus, submitType));
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

五.前端angularJS显示方案
目前市面上多种浏览器对报表的支持程度不一,最优解决方案如下:
ie十以上支持下载,谷歌火狐浏览器可在线预览
html:

<div class="form-group" style="margin-left:90px">
        <input class="btn btn-success" type="button" style="width:100px;" value="打印报表"
               ng-click="report()"/>
      </div>
  • 1
  • 2
  • 3
  • 4

js

$scope.report = function () {
        if (window.navigator && window.navigator.msSaveOrOpenBlob) {
          $http({
            url: $scope.URL + '?format=pdf&companyId=' + $scope.companyId + '&issue=' + $scope.issue,
            method: 'GET',
            responseType: 'arraybuffer'
          }).success(function (response) {
            var file = new Blob([response], {type: 'application/pdf'});
            var fileURL = URL.createObjectURL(file);
            window.navigator.msSaveOrOpenBlob(file);
          });
        } else {
          var reportOption = {};
          reportOption.pdfName = $scope.title;
          reportOption.method = 'GET';
          reportOption.url = $scope.URL + '?format=pdf&companyId=' + $scope.companyId + '&issue=' + $scope.issue;
          reportOption.headers = {Accept: '*/*'};
          reportHelper.showReport(reportOption);

        }
      };
  **五.从ftp服务器获取方案**   

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

@RestController
@RequestMapping(ApplyPrintController.BASE_URL)
public class ApplyPrintController {

/** 根路径 */
public final static String BASE_URL = "/reports/applyReport";

@RequestMapping(method = RequestMethod.GET)
public void printReport(@RequestParam("format") String format,
        @RequestParam(value = "companyId", required = true) String companyId,
        @RequestParam(value = "issue", required = false) Long issue, @RequestParam("buzzType") String buzzType,
        @RequestParam("submitType") String submitType,
        @RequestParam(value = "reviewedStatus", required = false) String reviewedStatus,
        @RequestParam(required = false) Long pageIndex, HttpServletRequest request, HttpServletResponse response) {

    String host = "10.154.227.46";// 设置服务器地址
    int port = 21; // 设置服务器端口号
    String username = "ftp2012";// 设置服务器访问用户
    String password = "dfca@123";// 设置服务器密码
    String remoteDir = "/ftpuser"; // 切换报表所在路径
    /** 文件路径通配符 */
    String regEx = "A20170020062.pdf";
    String encoding = System.getProperty("file.encoding"); // 设置编码
    FTPClient client = new FTPClient();
    // 设置超时时间
    client.setConnectTimeout(30000);
    try {
        // 1、连接服务器
        if (!client.isConnected()) {
            // 如果采用默认端口,可以使用client.connect(host)的方式直接连接FTP服务器
            client.connect(host, port);
            // 登录
            client.login(username, password);
            // 获取ftp登录应答码
            int reply = client.getReplyCode();
            // 验证是否登陆成功
            if (!FTPReply.isPositiveCompletion(reply)) {
                client.disconnect();
                throw new RuntimeException("未连接到FTP,用户名或密码错误。");
            } else {
                System.out.println("FTP连接成功。IP:" + host + "PORT:" + port);
            }
            // 2、设置连接属性
            client.setControlEncoding(encoding);
            // 设置以二进制方式传输
            client.setFileType(FTPClient.BINARY_FILE_TYPE);
            client.enterLocalPassiveMode();
        }
    } catch (SocketException e) {
        try {
            client.disconnect();
        } catch (IOException e1) {
        }
        throw new RuntimeException("连接FTP服务器失败" + e.getMessage());
    } catch (IOException e) {
    }
    InputStream stream = null;
    try {
        // 1、设置远程FTP目录
        client.changeWorkingDirectory(remoteDir);
        System.out.println("切换至工作目录【" + remoteDir + "】");
        stream = client.retrieveFileStream(regEx);
        int length = stream.available();
        if (length != -1) {
            byte[] buffer3 = new byte[1024];
            int readCount = 0;
            ServletOutputStream sos = response.getOutputStream();
            while ((readCount = stream.read(buffer3)) > 0) {
                sos.write(buffer3, 0, readCount);
            }
        }
    } catch (IOException e) {
        throw new RuntimeException("读取文件失败" + e.getMessage());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

}

  • 1

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多