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

报表在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 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) 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();
        }

    }

    }

三.单张报表生成后台代码详解
此方法使用最基本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();
    }

}
}

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

    <dependency>
            <groupId>org.apache.pdfboxgroupId>
            <artifactId>pdfbox-appartifactId>
            <version>1.8.13version>
    dependency>
@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();
        }

    }

}

四.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 getReportData(String format, String requestFullUri, CompanyLevyDTO dto,
            Long issue, String name, String companyNumber) {

        Map model = new HashMap();
        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 list) {
        Collection> collection = new ArrayList>();
        for (int i = 0; i < list.size(); i++) {
            Map map = new HashMap();
            LevyBodyDTO dto = list.get(i);
            map.put("insuranceCode", dto.getInsuranceCode());
    ...//这里面放循环的数据
            collection.add(map);
        }

        return new JRMapCollectionDataSource(collection);
    }
}

五.也可以使用直接返回前台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));
        }

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

class="form-group" style="margin-left:90px"> class="btn btn-success" type="button" style="width:100px;" value="打印报表" ng-click="report()"/>

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服务器获取方案

@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());
        }
    }
}

六.实现导出Excel格式
“““

    OrganizationApply company = organizationApplyService.findByOrgId(companyId);
    List dtolist = new ArrayList<>();
    QueryCompanyPaymentInfoDTO qcpdto = new QueryCompanyPaymentInfoDTO(companyId, issueBegin, issueEnd);
    CompanyPaymentInfo companyPaymentInfo = companyPaymentReportPrintService.queryCompanyPaymentInfo(qcpdto);
    if (companyPaymentInfo.getCompanyPaymentBasicDTO() == null
            || companyPaymentInfo.getCompanyPaymentDTOList().size() == 0) {
        resource = ctx.getResource("classpath:/reports/rptEmpty.jrxml");
    } else {
        dtolist = companyPaymentInfo.getCompanyPaymentDTOList();
        resource = ctx.getResource("classpath:/reports/rptCompanyPayment.jrxml");
    }

    // 打印报表
    InputStream inputStream;
    try {
        // 译为输入流
        inputStream = resource.getInputStream();
        // 编译报表
        JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);

        Map map = new HashMap<>();

        // 报表打印实现
        if (companyPaymentInfo.getCompanyPaymentBasicDTO() == null
                || companyPaymentInfo.getCompanyPaymentDTOList().size() == 0) {
            // 空报表
            map = DefaultEmptyFactory.getReportData(format, requestFullUri);
        } else {
            map = CompanyPaymentPrintFactory.getReportData(format, requestFullUri, dtolist, company,
                    companyPaymentInfo, issueBegin, issueEnd);
        }                   
        JasperPrint print = JasperFillManager.fillReport(jasperReport, map,CompanyPaymentPrintFactory.mapData(dtolist));                    

        JRAbstractExporter exporter = new JRXlsExporter();
        response.reset();
        response.setContentType("application/vnd.ms-execl");
        response.setHeader("Content-Disposition",
                "attachment;filename=" + new String("单位缴费清单".getBytes("gbk"), "iso8859-1") + ".xls");
        JasperReportsUtils.render(exporter, print, response.getOutputStream());

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

}
“`

你可能感兴趣的:(java生成报表)