Alguém já iniciou a confecção de relatórios PDF/HTML ou outro tipo com Jasper ou JFree e VRaptor 3?
Deixe uma dica além do que consta na documentação. Vai ajudar os menos experientes como eu
Ola Cinei!
Basta você devolver um InputStream com seu método, que o vraptor providenciará o resultado como um download.
Caso você queira fazer algo mais rebuscado, para setar alguns valores do header de resposta, receba HttpServletResponse no seu construtor, para que essa seja injetada, e lá você configura o tipo, tamanho e nome do arquivo, para que o download seja feito de maneira mais elegante!
Silveira,
obrigado pelas dicas. Devo iniciar logo o primeiro.
Na maioria das vezes a nova versão possui mais facilidades.
Parabens a todos envolvidos.
Você pode retornar na sua lógica um InputStream, ou um Download:
@Resource
public class RelatorioController {
public Download geraRelatorio() {
InputStream pdf = //gera o pdf;
String contentType = "application/pdf";
String fileName = "relatorio.pdf";
return new InputStreamDownload(pdf, contentType, fileName);
}
}
Oi Lucas!
Seria legal tambem poder passar como argumento o tamanho do arquivo, assim os browsers conseguem mostrar a estimativa de quanto falta!
Que tal uma issue pro 3.01?
paulo
Por mim tudo bem =)
Como eu quero deixar bem flexivel, peguei o seguinte caminho que ficou meio longo:
Intercept
@Intercepts
@RequestScoped
public class DownloadInterceptor implements Interceptor {
private ClientOutput clientOutput;
private HttpServletResponse response;
private ServletContext sc;
public DownloadInterceptor(HttpServletResponse response, ServletContext sc, ClientOutput clientOutput) {
this.response = response;
this.sc = sc;
this.clientOutput = clientOutput;
}
public void intercept(InterceptorStack stack, ResourceMethod method, Object resourceInstance)
throws InterceptionException {
clientOutput.setResponse(response);
clientOutput.setServletContext(sc);
stack.next(method, resourceInstance);
}
public boolean accepts(ResourceMethod method) {
return true;
}
}
Componete com HttpServletResponse isolado e que será injetado no Resource
@Component
public class ClientOutput {
private HttpServletResponse response;
private ServletContext sc;
public void setResponse(HttpServletResponse response){
this.response = response;
}
public void setServletContext(ServletContext sc){
this.sc = sc;
}
public void setNoCache (){
this.response.setHeader ("Pragma", "public");
this.response.setHeader("Cache-control", "must-revalidate");
}
public ServletOutputStream getOutputStream() throws IOException {
return response.getOutputStream();
}
public HttpServletResponse getResponse(){
return this.response;
}
public File getFile(String relatorio) throws IOException {
File reportFile = new File(this.sc.getRealPath(relatorio));
return reportFile;
}
public String getPath(String caminho) throws IOException {
return sc.getRealPath("/WEB-INF/relatorios/")+File.separator;
}
public void setContentType(String type) {
response.setContentType(type);
}
}
Método da classe que gera o Relatório quando for usar JRBeanCollectionDataSource
@SuppressWarnings("unchecked")
public void relatorioJrds (ClientOutput clientOutput, List dados, String relatorio, HashMap<Object, Object> parameters) {
this.clientOutput = clientOutput;
this.clientOutput.setNoCache();
try {
JRDataSource jrds = new JRBeanCollectionDataSource(dados);
byte[] bytes = null;
try {
bytes = JasperRunManager.runReportToPdf(this.clientOutput.getFile(relatorio).getPath(), parameters, jrds);
} catch (Exception e) {
e.printStackTrace();
return;
}
if (bytes != null && bytes.length > 0) {
clientOutput.getResponse().setContentLength(bytes.length);
this.clientOutput.getOutputStream().write(bytes, 0, bytes.length);
this.clientOutput.getOutputStream().flush();
this.clientOutput.getOutputStream().close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Resource
public CompradorController(DaoFactory daoFactory, Result result, ClientOutput clientOutput) {
.
.
.
@SuppressWarnings("unchecked")
public void geraRelatorio(String coluna, String texto) {
this.compradorRegra.listar(coluna, texto, 1, 99, coluna);
List dados = this.compradorRegra.getCompradors();
Relatorios relat = new Relatorios(this.clientOutput, "application/pdf");
relat.setTituloRelatorio("Comprador");
relat.setCabecalho(this.daoFactory);
relat.setNomeRelatorio("Comprador.jasper");
relat.relatorioJrds(dados);
}
Método utilizado acima (da Classe Relaorios):
@SuppressWarnings("unchecked")
public void relatorioJrds(List dados) {
new ReportGenerator().relatorioJrds(this.clientOutput, dados, this.nomeRelatorio, this.parameters);
}
Complexo demais?
Mas o problema é que vem a mensagem:
O VRaptor pode te ajudar em muitas coisas que você fez:
Você não precisa do DownloadInterceptor, pode apagá-lo, basta receber o Response e o ServletContext no construtor do
ClientOutput:
@Component
public class ClientOutput {
private final HttpServletResponse response;
private final ServletContext sc;
public ClientOutput(HttpServletResponse response, ServletContext context) {
this.response = response;
this.sc = context;
}
//...
}
Você pode apenas retornar um InputStream com o Pdf gerado, daí não precisa escrever o OutputStream na mão:
@SuppressWarnings("unchecked")
public InputStream relatorioJrds (ClientOutput clientOutput, List dados, String relatorio, HashMap<Object, Object> parameters) {
this.clientOutput = clientOutput;
this.clientOutput.setNoCache();
try {
JRDataSource jrds = new JRBeanCollectionDataSource(dados);
byte[] bytes = null;
try {
bytes = JasperRunManager.runReportToPdf(this.clientOutput.getFile(relatorio).getPath(), parameters, jrds);
} catch (Exception e) {
e.printStackTrace();
return;
}
if (bytes != null && bytes.length > 0) {
clientOutput.getResponse().setContentLength(bytes.length);
return new ByteArrayInputStream(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
}
o erro que tá dando é que você não falou pro VRaptor que você já escreveu a resposta da requisição, e então ele tentou
fazer o forward pra página padrão (…/relatorioJrds.jsp). Quando você mexe no output Response você tem que fazer a chamada:
result.use(Results.nothing()); pro vraptor não redirecionar pra página padrão…
e outra coisa: receba o ClientOutput no construtor do controller…
[]'s
Muito bom. Obrigado.
Acredito que agora conseguirei chegar onde preciso.
Valeu …ainda não me acostumei com a possibilidade de injetar quase tudo e com mais facilidades.
Resolvido da forma que perguntei. Estou enviando um objeto já populado
Agradeço a todos que ajudou.
Meu próximo desafio e conseguir utilizar conexão com Jasper via JNDI, se é que é possível.