Search code examples
javaajaxspringjasper-reports

Report is fine in backend but it is received empty when downloaded using ajax from spring boot


My stack

Spring boot 1.5.6
JasperReport
Ajax JQuery 3.1.1

My goal

I'm trying to print for first time a report using jasper report, I have a printing service where I have my reports stored, my idea was to send http request via ajax containing data and get a pdf report

What I tried

I have a rest controller in my spring-boot backend which is implemented like this

@RestController
@RequestMapping(PrintController.API)
public class PrintController {
    public static final String API="print";

    @PostMapping("client")
    public void export(@RequestBody List<ClientJsonDto> datas,HttpServletResponse response){

        System.out.println(datas);
         JRBeanCollectionDataSource itemsJRBean = new JRBeanCollectionDataSource(datas);

    /* Map to hold Jasper report Parameters */
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("ItemDataSource", itemsJRBean);

    byte[] bytes = generatePDFReport("refclient", parameters);
    return ResponseEntity
              .ok()
              // Specify content type as PDF
              .header("Content-Type", "application/pdf; charset=UTF-8")
              // Tell browser to display PDF if it can
              .header("Content-Disposition", "attachment;inline; filename=\"client.pdf\"")
              .body(bytes);
       
    }


public byte[] generatePDFReport(String inputFileName, Map<String, Object> params) {
    return generatePDFReport(inputFileName, params, new JREmptyDataSource());
}

    
public File loadJasperFile(String file) {
    
    try {
        return ResourceUtils.getFile("classpath:static/reports/"+file+".jasper");
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    };
    return null;
}

public byte[] generatePDFReport(String inputFileName, Map<String, Object> params,
        JRDataSource dataSource) {
        byte[] bytes = null;
        JasperReport jasperReport = null;
        try (ByteArrayOutputStream byteArray = new ByteArrayOutputStream()) {
          // Check if a compiled report exists


            jasperReport = (JasperReport) JRLoader.loadObject(loadJasperFile(inputFileName));
          
          // Compile report from source and save
       
          JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, dataSource);
          // return the PDF in bytes
          bytes = JasperExportManager.exportReportToPdf(jasperPrint);
        }
        catch (JRException | IOException e) {
          e.printStackTrace();
        }
        return bytes;
      }

}

my report is as below

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Created with Jaspersoft Studio version 7.2.0.final using JasperReports Library version 6.6.0  -->
    <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="refClient" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" isIgnorePagination="true" uuid="576dcd38-2982-412b-93d5-2a078da1b183">
        <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
        <style name="Table_TH" mode="Opaque" backcolor="#F0F8FF">
            <box>
                <pen lineWidth="0.5" lineColor="#000000"/>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <leftPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
                <rightPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <style name="Table_CH" mode="Opaque" backcolor="#BFE1FF">
            <box>
                <pen lineWidth="0.5" lineColor="#000000"/>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <leftPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
                <rightPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <style name="Table_TD" mode="Opaque" backcolor="#FFFFFF">
            <box>
                <pen lineWidth="0.5" lineColor="#000000"/>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <leftPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
                <rightPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <style name="Table 1_TH" mode="Opaque" backcolor="#F0F8FF">
            <box>
                <pen lineWidth="0.5" lineColor="#000000"/>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <leftPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
                <rightPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <style name="Table 1_CH" mode="Opaque" backcolor="#BFE1FF">
            <box>
                <pen lineWidth="0.5" lineColor="#000000"/>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <leftPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
                <rightPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <style name="Table 1_TD" mode="Opaque" backcolor="#FFFFFF">
            <box>
                <pen lineWidth="0.5" lineColor="#000000"/>
                <topPen lineWidth="0.5" lineColor="#000000"/>
                <leftPen lineWidth="0.5" lineColor="#000000"/>
                <bottomPen lineWidth="0.5" lineColor="#000000"/>
                <rightPen lineWidth="0.5" lineColor="#000000"/>
            </box>
        </style>
        <subDataset name="ItemDataset" uuid="2914f7c6-c2d7-448b-b0c1-090970e18ed6">
            <queryString>
                <![CDATA[]]>
            </queryString>
            <field name="clientName" class="java.lang.String"/>
            <field name="identifiant" class="java.lang.String"/>
            <field name="codeExterne" class="java.lang.String"/>
        </subDataset>
        <parameter name="ItemDataSource" class="net.sf.jasperreports.engine.data.JRBeanCollectionDataSource"/>
        <queryString>
            <![CDATA[select 1 from dual]]>
        </queryString>
        <background>
            <band splitType="Stretch"/>
        </background>
        <title>
            <band height="50">
                <staticText>
                    <reportElement x="11" y="11" width="100" height="30" uuid="9d66bc1e-2b6d-49b7-8a64-74fbd2e5d5eb"/>
                    <text><![CDATA[Liste des clients]]></text>
                </staticText>
            </band>
        </title>
        <detail>
            <band height="256" splitType="Stretch">
                <componentElement>
                    <reportElement x="0" y="0" width="555" height="200" uuid="7786bb05-503a-4b6a-991a-a7bcf3abad07">
                        <property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
                        <property name="com.jaspersoft.studio.table.style.table_header" value="Table 1_TH"/>
                        <property name="com.jaspersoft.studio.table.style.column_header" value="Table 1_CH"/>
                        <property name="com.jaspersoft.studio.table.style.detail" value="Table 1_TD"/>
                    </reportElement>
                    <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
                        <datasetRun subDataset="ItemDataset" uuid="d3e1e03a-2c83-4436-9e50-79518bc3d337">
                            <dataSourceExpression><![CDATA[$P{ItemDataSource}]]></dataSourceExpression>
                        </datasetRun>
                        <jr:column width="130" uuid="dca8961f-ce2d-47ac-879c-b15847d170a9">
                            <property name="com.jaspersoft.studio.components.table.model.column.name" value="Colonne1"/>
                            <jr:tableHeader style="Table 1_TH" height="30" rowSpan="1">
                                <staticText>
                                    <reportElement x="0" y="0" width="130" height="30" uuid="f60d1675-6fb6-4569-93ca-de32b3a8e861"/>
                                    <box>
                                        <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                    </box>
                                    <text><![CDATA[Nom]]></text>
                                </staticText>
                            </jr:tableHeader>
                            <jr:detailCell style="Table 1_TD" height="30">
                                <textField>
                                    <reportElement x="0" y="0" width="130" height="30" uuid="f1de366a-b36f-4200-9b1e-7a0009be5373"/>
                                    <box>
                                        <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                    </box>
                                    <textFieldExpression><![CDATA[$F{clientName}]]></textFieldExpression>
                                </textField>
                            </jr:detailCell>
                        </jr:column>
                        <jr:column width="140" uuid="980fffb5-1088-47a6-b00f-b5d08b7093c9">
                            <property name="com.jaspersoft.studio.components.table.model.column.name" value="Colonne2"/>
                            <jr:tableHeader style="Table 1_TH" height="30" rowSpan="1">
                                <staticText>
                                    <reportElement x="0" y="0" width="140" height="30" uuid="16679b95-2e6e-4ca1-b8b6-dd7b74267c56"/>
                                    <box>
                                        <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                    </box>
                                    <text><![CDATA[Identifiant]]></text>
                                </staticText>
                            </jr:tableHeader>
                            <jr:detailCell style="Table 1_TD" height="30">
                                <textField>
                                    <reportElement x="0" y="0" width="140" height="30" uuid="341e7faf-9680-4941-a9a4-ac78b8f4aae0"/>
                                    <box>
                                        <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                    </box>
                                    <textFieldExpression><![CDATA[$F{identifiant}]]></textFieldExpression>
                                </textField>
                            </jr:detailCell>
                        </jr:column>
                        <jr:column width="100" uuid="761d1134-6b53-4b5d-9355-b44586d8d8aa">
                            <property name="com.jaspersoft.studio.components.table.model.column.name" value="Colonne3"/>
                            <jr:tableHeader style="Table 1_TH" height="30" rowSpan="1">
                                <staticText>
                                    <reportElement x="0" y="0" width="100" height="30" uuid="b07f5db5-1df8-48e9-a612-27ad6110fdcd"/>
                                    <box>
                                        <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                    </box>
                                    <text><![CDATA[Code]]></text>
                                </staticText>
                            </jr:tableHeader>
                            <jr:detailCell style="Table 1_TD" height="30">
                                <textField>
                                    <reportElement x="0" y="0" width="100" height="30" uuid="1e0438b1-82e5-429a-b63a-5349014cf84a"/>
                                    <box>
                                        <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                        <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/>
                                    </box>
                                    <textFieldExpression><![CDATA[$F{codeExterne}]]></textFieldExpression>
                                </textField>
                            </jr:detailCell>
                        </jr:column>
                    </jr:table>
                </componentElement>
            </band>
        </detail>
    </jasperReport>

as you see I'm using a parameters where I send a jrcollection, this is used in a tutorial that I found on YouTube.

for the response handling I have this js ajax call

$(document).on('click', '#menu0-func1-menu0-func1', function(){
        console.log(printData);
        var jsonData =JSON.parse(JSON.stringify(printData));
            var settings = {
                "async" : true,
                "crossDomain" : true,
                "url" : "http://"+document.location.host+"/facturation/print/client",
                "method" : "POST",
                "headers" : {
                    "cache-control" : "no-cache",
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                },
                "processData" : false,
                "contentType" : "application/json",
                "dataType" : "text",
                "data" : JSON.stringify(printData)
            }

            $.ajax(settings).done(function(response, status, xhr) {
                console.log(response);
                  
                // check for a filename
                var filename = "";
                var disposition = xhr.getResponseHeader('Content-Disposition');
                if (disposition && disposition.indexOf('attachment') !== -1) {
                    var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                    var matches = filenameRegex.exec(disposition);
                    if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
                }

                var type = xhr.getResponseHeader('Content-Type');
                var blob = new Blob([response], { type: type });

                if (typeof window.navigator.msSaveBlob !== 'undefined') {
                    // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
                    window.navigator.msSaveBlob(blob, filename);
                } else {
                    var URL = window.URL || window.webkitURL;
                    var downloadUrl = URL.createObjectURL(blob);

                    if (filename) {
                        // use HTML5 a[download] attribute to specify filename
                        var a = document.createElement("a");
                        // safari doesn't support this yet
                        if (typeof a.download === 'undefined') {
                            window.location = downloadUrl;
                        } else {
                            a.href = downloadUrl;
                            a.download = filename;
                            document.body.appendChild(a);
                            a.click();
                        }
                    } else {
                        window.location = downloadUrl;
                    }

                    setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
                }
            
            });
    });

there is no exception, Normally I should at least get the title of the report but I m getting an empty pdf page

here is my console log in Chrome

    %PDF-1.5
    %����
    3 0 obj
    <</Filter/FlateDecode/Length 882>>stream
    x���[O1���W��>�z|�M^i�J�B�T��e�Q��`����zJc�����}|2_���hU�R,d)Vuq�*�J�u!�W�{a�X�w' @�US�Y�t��D��ޤ�)�e��Ӧ8��m�ע^���n��n�#���9��O�\�ג�K��Rֺw�����
    �r��59��>/� 0^���r�`ޙ�ֈ�h�!�`�/���5�KƆ��Yb�\
    #��1hP�
    �ďK.fYyk?���%�6T�!�}�˾(j�on7����M���?F6���V��F�M^&�IjywI�h��������WV1d���L2N�w��̦%�E�c�B��I��єB�R��b!�2�f���d=*�I�����"�KB�"
    ��᳍&�������ֲX�df2��C"�zf�#)Ό�wLJ��F����аH��E#
    ��%/!b=��,�"y�XKyA˿��e
    endstream
    endobj
    1 0 obj
    <</Tabs/S/Group<</S/Transparency/Type/Group/CS/DeviceRGB>>/Contents 3 0 R/Type/Page/Resources<</ColorSpace<</CS/DeviceRGB>>/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]/Font<</F1 2 0 R>>>>/Parent 4 0 R/MediaBox[0 0 595 842]>>
    endobj
    5 0 obj
    [1 0 R/XYZ 0 852 0]
    endobj
    2 0 obj
    <</Subtype/Type1/Type/Font/BaseFont/Helvetica/Encoding/WinAnsiEncoding>>
    endobj
    4 0 obj
    <</Kids[1 0 R]/Type/Pages/Count 1/ITXT(2.1.7)>>
    endobj
    6 0 obj
    <</Names[(JR_PAGE_ANCHOR_0_1) 5 0 R]>>
    endobj
    7 0 obj
    <</Dests 6 0 R>>
    endobj
    8 0 obj
    <</Names 7 0 R/Type/Catalog/Pages 4 0 R/ViewerPreferences<</PrintScaling/AppDefault>>>>
    endobj
    9 0 obj
    <</ModDate(D:20181123161409Z)/Creator(JasperReports Library version 6.4.0)/CreationDate(D:20181123161409Z)/Producer(iText 2.1.7 by 1T3XT)>>
    endobj
    xref
    0 10
    0000000000 65535 f 
    0000000964 00000 n 
    0000001240 00000 n 
    0000000015 00000 n 
    0000001328 00000 n 
    0000001205 00000 n 
    0000001391 00000 n 
    0000001445 00000 n 
    0000001477 00000 n 
    0000001580 00000 n 
    trailer
    <</Info 9 0 R/ID [<b7d27a6f96e6278f5c1d222f79d7c999><b97ae89e1e568703aeb75af2080d04d8>]/Root 8 0 R/Size 10>>
    startxref
    1735
    %%EOF

What to do, I tried lot of tutorials this 3 last days but no success

edit

I generated the pdf using JasperExportManager.exportReportToPdfFile(jasperPrint, "rapport.pdf"); and the pdf file is well formed that is there, I compared the txt representation of this well pdf with the received log, they are the same, my empty pdf is 3kb and the well formed is also 3kb.


Solution

  • I have tried your javascript code and there's an issue indeed.

    But the issue comes from within jQuery's ajax implementation. It does not properly handle the response data type.

    This post here presents two alternatives: either use the XMLHttpRequest object directly or use a custom jQuery plugin designed specifically for this issue.

    Another option could be to split your controller logic in two parts:

    • on the first request you would fill in the report parameters
    • on the second one you would produce the PDF output; you could even have this opened in a new tab and skip the whole AJAX part.