Gerar Relatorio e abrir em uma nova aba

Estou fazendo um trabalho da faculdade e preciso gerar um relatório de vendas por cliente. Eu gostaria que esse relatório fosse aberto em uma nova aba do navegador, eu criei um servlet para gerenciar apenas a emissão dos relatórios:

[code] protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType(“application/pdf”);

    String gerenciamento = request.getParameter("gerenciamento");
    ServletContext context = request.getSession().getServletContext();
    HttpSession session = request.getSession();

    if(gerenciamento.equals("notafiscal"))
    {
        gerarRelatorio relatorio = new gerarRelatorio();

        String id = request.getParameter("idvenda");
        int idVenda= Integer.parseInt(id);

        VendaDAO dao = new VendaDAO();

        
        String path = context.getRealPath("Relatorios/notaFiscal.jrxml");
           
        byte[] bytes = relatorio.notaFiscalVenda(path, idVenda);

        if(bytes!=null && bytes.length > 0)
        {
            response.setContentLength(bytes.length);
            ServletOutputStream ouputStream = response.getOutputStream();
            ouputStream.write(bytes, 0, bytes.length);
            ouputStream.flush();
            ouputStream.close();
        }
    }

    
} 

[/code]

O metodo da classe gerarRelatorio que faz todo o trabalho e esse:

public byte[] notaFiscalVenda(String path,int idVenda)
    {
        Map<String,Integer> map = new HashMap<String, Integer>();
        map.put("idVenda", idVenda);
        byte[] bytes = null;

        try
        {
            JasperDesign design = JRXmlLoader.load(path);
            JasperReport report = JasperCompileManager.compileReport(design);
            bytes = JasperRunManager.runReportToPdf(report,map,conn);


            
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }

        return bytes;

    }

Mas ao executar o código acima eu recebo o seguinte erro:

java.lang.IllegalStateException: getWriter() has already been called for this response
	org.apache.catalina.connector.Response.getOutputStream(Response.java:579)
	org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:183)
	com.farmatads.dao.svGerarRelatorioController.processRequest(svGerarRelatorioController.java:61)
	com.farmatads.dao.svGerarRelatorioController.doGet(svGerarRelatorioController.java:88)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	com.farmatads.Controller.svRelatorioController.processRequest(svRelatorioController.java:60)
	com.farmatads.Controller.svRelatorioController.doGet(svRelatorioController.java:118)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

Já procurei por todo o forum como resolver isso mas nada.
Agradeço desde já

pra abrir em outra aba use um target=‘blank’ no seu botao de comando ,jah este erro ai eu ja tive problemas com isso ,mas faz muito tempo e naum me lembro como resolvi isso, tente assim pra ver

	OutputStream out = response.getOutputStream();
				out.write(bytes);
				out.flush();

Obrigado pela ajuda cara, mas continua dando o mesmo erro. Eu modifiquei a linha desta maneira:

OutputStream ouputStream = response.getOutputStream();
ouputStream.write(bytes);
ouputStream.flush();

E o erro persiste:

java.lang.IllegalStateException: getWriter() has already been called for this response
	org.apache.catalina.connector.Response.getOutputStream(Response.java:579)
	org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:183)
	com.farmatads.Controller.svGerarRelatorioController.processRequest(svGerarRelatorioController.java:62)
	com.farmatads.Controller.svGerarRelatorioController.doPost(svGerarRelatorioController.java:96)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	com.farmatads.Controller.svRelatorioController.processRequest(svRelatorioController.java:60)
	com.farmatads.Controller.svRelatorioController.doPost(svRelatorioController.java:131)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

Você está chamando direto essa servlet ou está dando um foward antes?

Boa Noite deniswsrosa.

eu estou chamando ele apartir de uma outra servlet usando o forward.

Este é o problema, vc faz alguma coisa na servlet anterior que “gera o response”, quando vc dá o forward pra essa Servlet a “resposta para o usuário” já foi gerada, quando vc tenta colocar os bytes do relatório gerado no response ele lança essa excessão falando que o " getWriter() já foi chamado".

Tente chamar essa servlet diretamente, verá que ela funciona normalmente.
PS: Poste a sua servlet anterior para vermos oque podemos fazer.

Boa tarde Turma.

Como vc me pediu deniswsrosa aqui esta a minha servlet que chama a segunda sevlet que gera o relatório. A servlet desse código eu uso para controlar o fluxo do sistema e a segunda servlet apenas para gerar o relatorio

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
    {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        String gerenciamento = request.getParameter("gerenciamento");
        ServletContext context = request.getSession().getServletContext();
        HttpSession session = request.getSession();

        if(gerenciamento.equals("notafiscal"))
        {

            int idVenda = 0;
            VendaDAO vendadao = new VendaDAO();
            
            try
            {
                String id = request.getParameter("idvenda");
                idVenda= Integer.parseInt(id);
                Venda venda = vendadao.getVenda(idVenda);
                if(venda!=null)
                {
                    RequestDispatcher rd = request.getRequestDispatcher("/svGerarRelatorioController?gerenciamento=notafiscal&idvenda="+idVenda);
                    rd.forward(request, response);
                }
                else
                {
                    out.println("A Venda Não Foi Encontrada");
                    RequestDispatcher rd = request.getRequestDispatcher("Relatorios/pesquisaRelatorio.jsp");
                    rd.include(request, response);
                }


            }catch(NumberFormatException ex)
            {
                out.println("Numero Informado Não é Válido");
                RequestDispatcher rd = request.getRequestDispatcher("Relatorios/pesquisaRelatorio.jsp");
                rd.include(request, response);
            }



        }

      out.close();


}

ps: eu segui as suas dicas e consegui gerar o relatório chamando diretamente a servlet que gera o relatório a partir de um formulário em uma página JSP. Mas eu gostaria de uma servlet para controlar o fluxo da aplicação e validar os valores passados pelos formulários.

Boa noite Turma.

Consegui resolver o problema.

Abaixo esta como modifiquei meu código:

No Servlet que controla o fluxo da aplicação e chamava o servlet que gera o relatório fiz essas modificações:

// Como Estava
RequestDispatcher rd = request.getRequestDispatcher("/FarmaTads/svGerarRelatorioController?gerenciamento=notafiscal&idvenda="+idVenda);
rd.forward(request, response);

//Modifiquei para essa forma
response.sendRedirect("/FarmaTads/svGerarRelatorioController?gerenciamento=notafiscal&idvenda="+idVenda);

No servlet que gera o relatório fiz essas modificações:

// inclui essa linha
response.setHeader("Content-Disposition", "attachment; filename=NotaFiscal.pdf");

E modifiquei o método da classe gerarRelatorio dessa forma:

public byte[] notaFiscalVenda(String path,int idVenda)
    {
        Map<Object,Object> map = new HashMap<Object, Object>();
        map.put("idVenda", idVenda);
        map.put("",path+"notaFiscal.jasper");
        byte [] bytes = null;

        try
        {   
            JasperPrint print =  JasperFillManager.fillReport(path+"notaFiscal.jasper", map, conn);
            bytes = JasperExportManager.exportReportToPdf(print);
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }

        return bytes;

    }

Tive esse problema de abrir e/ou salvar o relatório gerado, pelo comportamento do jasper pude perceber o seguinte:

Tem duas formas setar o cabeçalho, a primeira e colocando “attachment” como parâmetro.

response.setHeader(“Content-Disposition”, “attachment; filename=”"+ nomeArquivo + “”");

Desta maneira o navegador entende que o link é um arquivo para baixar e vai abrir a pop-up de download.

A outra forma é setando “inline” .

response.setHeader(“Content-Disposition”, “inline; filename=”"+ nomeArquivo + “”");
response.setContentType(“application/pdf”);

O navegador abre o relatório em uma nova janela ou aba, dependendo do target que você colocou no LINK ou por JS window.open().
Outra dica é que quando usar inline declare sempre o cabeçalho antes do tipo de documento senão ele se comporta como “attachment” e pede pra salvar antes de abrir o documento.

Espero que isso ajude alguém. :slight_smile:

1 curtida