12
respostas

Relatório em branco - Spring Boot

Bom, estou gerando um relatório com o Jasper Report 6.4.3 na minha API rest com o Spring Boot. Quando retorno o pdf ele vem totalmente em branco, mas com a quantidade de páginas corretas.

Nenhum erro é estorado no front-end nem no back-end. Quando testo a requisão no Postman, funciona corretamente. Já tentei diversas abordagens, como colocar

whenNoDataType="AllSectionsNoDetail"

nas propriedades do .jrxml.

12 respostas

Oi Pedro,

uma duvidas:

Com postman o relatório é preenchido corretamente e PDF está ok? Se isso for o caso, me parece ser um problema na hora de montar a requisição http no seu front.

abs

Olá Nico,

então acredito que não seja a requisição HTTP, pois estou conseguindo baixar outros pdfs da web, com um get. Estou usando um módulo do npm chamado downloadjs.

abs

Oi Pedro,

preciso de mais infos para realmente ajudar:

  • O que vc está usando no front-end?
  • Tem como mostrar a implementacao do controler aqui?
  • Aquele donwloadjs é seu cliente que envia a requisição?

obrigado, Nico

No front-end estou utilizando react, meu controller está dessa forma

@Controller
public class RelatorioController {

    @Autowired
    private DataSource dbsource;

    @RequestMapping(value = "gerarRelatorio", method = org.springframework.web.bind.annotation.RequestMethod.POST, produces = MediaType.APPLICATION_PDF_VALUE)
    public @ResponseBody ResponseEntity<InputStreamResource> gerarRelatorio(@RequestBody String json) {
        Relatorio relatorio;

        try {

            relatorio = new Relatorio(new JSONObject(json));
            ByteArrayInputStream stream = relatorio.toByteArrayInputStream(dbsource);

            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Disposition", "inline; filename=" + relatorio.getNome());

            return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_PDF)
                    .body(new InputStreamResource(stream));
        } catch (JSONException | IOException | JRException | SQLException e) {
            return null;
        }
    }

}

e o metódo da classe Relatorio toByteArrayInputStream(dbsource) faz o seguinte:

public ByteArrayInputStream toByteArrayInputStream(DataSource dataSource)
            throws JRException, SQLException, IOException {

        compileJrxml();

        Map<String, Object> params = new HashMap<String, Object>();
        JasperPrint jasperPrinted = JasperFillManager.fillReport(
                RelatorioKeys.JASPER_FILE_PATH + RelatorioKeys.JASPER_FILE_NAME, params, dataSource.getConnection());
        JRPdfExporter exporter = new JRPdfExporter();
        ByteArrayOutputStream byteArrayOuputStream = new ByteArrayOutputStream();

        File pdf = new File(RelatorioKeys.JASPER_FILE_PATH + nome);

        exporter.setExporterInput(new SimpleExporterInput(jasperPrinted));
        exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(pdf));

        exporter.exportReport();

        byte[] byteArray = IOUtils.toByteArray(new FileInputStream(pdf));
        byteArrayOuputStream.write(byteArray);

        return new ByteArrayInputStream(byteArrayOuputStream.toByteArray());

    }

No front-end com react recebo assim:

requestHandler.post('/gerarRelatorio', {})
                .then(data => {
                    download(data, 'relatorio.pdf', 'application/pdf');
                })
                .catch(err => {
                    swal(
                        'Erro ao fazer requisição',
                        `Erro: ${err}`,
                        'error'
                    );
                });

Sendo este RequestHandler uma classe que fiz para encapsular os detalhes gerais das request, como o banco, a porta e cross-origin,

Obrigado, Pedro

Oi Pedro,

Repare que vc está "engolindo" a exceção:

}catch (JSONException | IOException | JRException | SQLException e) {
            return null;
}

Aconselho logar a exceção e devolver badRequest() através do ResponseEntity. Isso deve ajudar entender o real problema (espero eu!).

abs

Então, como disse antes não está lançando nenhuma exceção, esse tratamento de exceção tinha planejado melhorar-lo após a implementação do "caminho feliz ". E essa tá sendo o problema, na tá realmente funcionando, mas ao mesmo tempo não tá. Não é lançado nenhuma exceção e o http vai ok.

Abs

Oi Pedro,

novamente duvidas :)

  • para descobrir que não há exceção vc depurou a aplicação ou está usando testes automatizados?

  • sem react, vc já conseguiu acessar e testar o seu controller?

  • vc testou o seu método toByteArrayInputStream separadamente (sem spring e web app)?

nao vamos desistir!!

abs

Não estou implementando boas práticas de teste automatizados, com um JUnit ou outros frameworks, por exemplo. Mas depuro pelo eclipse mesmo, e realizo testes caixas pretas com o postman e o próprio front-end. Sei que não lança exceção, pois quando forço uma, tipo passar um path inexistente do .jrmxl, retorna simplesmente vazio o body da request.

Consigo sim, inclusive tive o mesmo erro realizando a request com o javascript nativo. E tratando a response com javascript nativo, na prática a diferença tem sido verborrágica.

Como assim separadamente? Bom, acho que está ok, pois o pdf é criado normalmente e fica armazenado no meu servidor, inclusive.

vamos desistir não, hahahaha

abs

Oi Pedro,

continuando fazendo perguntas :)

  • Aquele File pdf que está gerando no servidor está corretamente preenchido? Sei que vc falou "normalmente", só para garantir.

  • Tem como fazer um teste e baixar um pdf que já existe? Quero dizer, testar o controller sem usar o JasperReport, apenas testar a criação da resposta, algo:

    //no controller
    ClassPathResource pdfFile = new ClassPathResource("downloads/" + nomeDoPdf);
    return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_PDF)
                      .body(new InputStreamResource(pdfFile.getInputStream()));

Aqui tem um exemplo mais completo do download.

posso estar muito enganado mas talvez algum stream não está fechado quando a resposta é gerado ....

abs

Olá Nico,

fiz o teste que vc sugeriu e em todos os casos foi lançado um File not found exception. Testei tanto com o pdf gerado dinamicamente pelo Jasper e quanto com um pdf statico que adicionei manualmente no projeto

abs

Oi Pedro,

a pasta downloads deve estar dentro da pasta src (ou com maven src/main/java).

Spring tbm oferece um FileSystemResource, por exemplo:

FileSystemResource res = FileSystemResource("/users/admin/downloads/relatorio.pdf");
InputStream is = res.getInputStream();

abs

Nico,

Ainda está ocorrendo o mesmo erro, está muito estranho ainda.

abs