Search code examples
javaspring-mvcjasper-reportspdf-generation

How to get jasperreport file (.JRXML) exact location to load to the system?


I trying to load jasper report (.jrxml) that i created, i named the report "JREmp1.xml". but i got this error

"HTTP Status 500 - Request processing failed; nested exception is net.sf.jasperreports.engine.JRException: java.io.FileNotFoundException: D:\printpdf.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\JasperExample\jasper\JREmp1.jrxml (The system cannot find the path specified)"

how to got the exact location? here is my JREmp1.xml file location : enter image description here

and here is code in my controller class :

@RequestMapping(value = "/generateReport", method = RequestMethod.POST)
public String generateReport(
        @Valid @ModelAttribute("jasperInputForm") JasperInputForm jasperInputForm,
        BindingResult result, Model model, HttpServletRequest request,
        HttpServletResponse response) throws JRException, IOException,
        NamingException {

    if (result.hasErrors()) {
        System.out.println("validation error occured in jasper input form");
        return "loadJasper";

    }

    String reportFileName = "JREmp1";
    JasperReportDAO jrdao = new JasperReportDAO();

    Connection conn = null;

    try {
        conn = jrdao.getConnection();

        String rptFormat = jasperInputForm.getRptFmt();
        String noy = jasperInputForm.getNoofYears();

        System.out.println("rpt format " + rptFormat);
        System.out.println("no of years " + noy);

        HashMap<String, Object> hmParams = new HashMap<String, Object>();

        hmParams.put("noy", new Integer(noy));

        hmParams.put("Title", "Employees working more than " + noy
                + " Years");

        JasperReport jasperReport = jrdao.getCompiledFile(reportFileName,
                request);

        if (rptFormat.equalsIgnoreCase("html")) {
            JasperPrint jasperPrint = JasperFillManager.fillReport(
                    jasperReport, hmParams, conn);
            jrdao.generateReportHtml(jasperPrint, request, response); // For
            // HTML
            // report
        }
        else if (rptFormat.equalsIgnoreCase("pdf")) {
            jrdao.generateReportPDF(response, hmParams, jasperReport, conn); // For
            // PDF
            // report
        }
    } catch (SQLException sqlExp) {
        System.out.println("Exception::" + sqlExp.toString());
    } finally {
        if (conn != null) {
            try {
                conn.close();
                conn = null;
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    return null;
}

Here is the code in my JasperReportDAO class :

public JasperReport getCompiledFile(String fileName, HttpServletRequest request) throws JRException {
    System.out.println("path " + request.getSession().getServletContext().getRealPath("/jasper/" + fileName + ".jasper"));
    File reportFile = new File( request.getSession().getServletContext().getRealPath("/jasper/" + fileName + ".jasper"));
    // If compiled file is not found, then compile XML template
    if (!reportFile.exists()) {
        JasperCompileManager.compileReportToFile(request.getSession().getServletContext().getRealPath("/jasper/" + fileName + ".jrxml"),request.getSession().getServletContext().getRealPath("/jasper/" + fileName + ".jasper"));
    }
    JasperReport jasperReport = (JasperReport) JRLoader.loadObjectFromFile(reportFile.getPath());
    return jasperReport;
}


public void generateReportHtml( JasperPrint jasperPrint, HttpServletRequest req, HttpServletResponse resp) throws IOException, JRException {
    HtmlExporter exporter=new HtmlExporter();
    List<JasperPrint> jasperPrintList = new ArrayList<JasperPrint>();
    jasperPrintList.add(jasperPrint);
    exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));
    exporter.setExporterOutput( new SimpleHtmlExporterOutput(resp.getWriter()));
    SimpleHtmlReportConfiguration configuration =new SimpleHtmlReportConfiguration();
    exporter.setConfiguration(configuration);
    exporter.exportReport();

}


public void generateReportPDF (HttpServletResponse resp, Map parameters, JasperReport jasperReport, Connection conn)throws JRException, NamingException, SQLException, IOException {
    byte[] bytes = null;
    bytes = JasperRunManager.runReportToPdf(jasperReport,parameters,conn);
    resp.reset();
    resp.resetBuffer();
    resp.setContentType("application/pdf");
    resp.setContentLength(bytes.length);
    ServletOutputStream ouputStream = resp.getOutputStream();
    ouputStream.write(bytes, 0, bytes.length);
    ouputStream.flush();
    ouputStream.close();
}

and here is my JasperInputForm class :

public class JasperInputForm {

    @NotEmpty
    private String noofYears;
    private String rptFmt="Html";

    public String getRptFmt() {
        return rptFmt;
    }

    public void setRptFmt(String rptFmt) {
        this.rptFmt = rptFmt;
    }

    public String getNoofYears() {
        return noofYears;
    }

    public void setNoofYears(String noofYears) {
        this.noofYears = noofYears;
    }

}

how to get my JREmp1.jrxml file location properly? I develop this report for Spring MVC application

UPDATE : Here is my complete function code after i update with @Wilson answer (i go with second option that @Wilson said) : this function is inside JasperReportDAO :

public JasperReport getCompiledFile(String fileName, HttpServletRequest request) throws JRException, MalformedURLException, URISyntaxException {
    System.out.println("path " + request.getSession().getServletContext().getRealPath("/jasper/" + fileName + ".jasper"));
    //File reportFile = new File( request.getSession().getServletContext().getRealPath("/jasper/" + fileName + ".jasper"));
    URL resourceUrl = request.getSession().getServletContext().getResource("/WEB-INF/jasper/" + fileName + ".jrxml");
    File reportFile = new File(resourceUrl.toURI());

    // If compiled file is not found, then compile XML template
    if (!reportFile.exists()) {
               JasperCompileManager.compileReportToFile(request.getSession().getServletContext().getRealPath("/jasper/" + fileName + ".jrxml"),request.getSession().getServletContext().getRealPath("/jasper/" + fileName + ".jasper"));
        }
        JasperReport jasperReport = (JasperReport) JRLoader.loadObjectFromFile(reportFile.getPath());
       return jasperReport;
}

and i got this error

"HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalArgumentException: URI scheme is not "file""

How to solve this?


Solution

  • There is a number of way to do to read file with ServeltContext:

    1. Use ServletContext#getRealPath

    String fullPath = request.getSession().getServletContext().getRealPath("/WEB-INF/jasper/" + fileName + ".jrxml");
    

    This will get you the full system path to the resource you are looking for. However, it will not work if the container do not expand the WAR file.

    2. Use ServletContext#getResource

    URL resourceUrl = request.getSession().getServletContext().getResource("/WEB-INF/jasper/" + fileName + ".jrxml");
    File file = new File(resourceUrl.toURI());
    

    This will return the URL no matter what container you use and where the application is installed.

    3. User ServletContext#getResourceAsStream

    InputStream resourceStream = request.getSession().getServletContext().getResourceAsStream("/WEB-INF/jasper/" + fileName + ".jrxml");
    

    This is an alternative of ServletContext#getResource to get an inputSteam

    UPDATE:

    The URL return from ServletContext#getResource may not be a file URL and it may cause issue. Please try ServletContext#getResourceAsStream with JasperCompileManager#compileReportToFile:

    JasperDesign jasperDesign = JRXmlLoader.load(resourceStream);
    JasperCompileManager.compileReportToFile(jasperDesign, jasperFilePath);
    

    I found that your are trying to write jasper report file into your program distribution which should be avoid. The preferred way is to pre-compile your report and put into your WAR file or put the compiled jasper report into a temporary directory.

    Following is full code example:

    public JasperReport getCompiledFile(String fileName, HttpServletRequest request) throws JRException, IOException {
        // Create temporary folder to store jasper report as you should not write a resource into your program
        // distribution
        String tempFolderPath = System.getProperty("java.io.tmpdir") + File.separator + "jasperReport";
        File tempFolder = new File(tempFolderPath);
        if (!tempFolder.exists()) {
            tempFolder.mkdirs();
        }
        String jasperFilePath = tempFolderPath + File.separator + fileName + ".jasper";
        File reportFile = new File(jasperFilePath);
        // If compiled file is not found, then compile XML template
        if (!reportFile.exists()) {
            InputStream jRXmlStream = request.getSession().getServletContext().getResourceAsStream
                    ("/WEB-INF/jasper/" + fileName + ".jrxml");
            JasperDesign jasperDesign = JRXmlLoader.load(jRXmlStream);
            JasperCompileManager.compileReportToFile(jasperDesign, jasperFilePath);
        }
        JasperReport jasperReport = (JasperReport) JRLoader.loadObjectFromFile(reportFile.getPath());
        return jasperReport;
    }