This question already has answers here:
How to provide a file download from a JSF backing bean?
(5 answers)
Closed 5 years ago.
I want to download a .txt/.log file saved in hard disk in JSF, am not getting any error but the issue is am not able to download the file, need some help..
note : am trying to zip the file first and then download.
I have tried :
response.setContentType("text/html");
response.setContentType("text/plain");
Code in page.xhtml:
<h:form>
<a4j:outputPanel id="downloadPanel">
<table><tr>
<td>
<h:commandButton id="dldFiles" title="Download File" image="/images/download.png"
style="width:20px; height:20px;"/>
</td>
<td>
<h:outputText value="Download log file" style="font-size: 11px; color:#56ADF8; font-weight: bold; cursor:pointer;"/>
</td>
</tr></table>
<a4j:support event="onclick" action="#{sqlLoaderAction.downloadFile}" reRender="uploadForm"></a4j:support>
</a4j:outputPanel>
</rich:panel>
</h:form>
In Actin Bean Methods:
public String downloadFile(){
System.out.println("--inside exportGoogleFeed--");
FacesContext fc = FacesContext.getCurrentInstance();
try{
User user = getUserBean();
Object sp = getServiceProxy(user);
HttpServletResponse response = ((HttpServletResponse)fc.getExternalContext().getResponse());
fc.responseComplete();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition","attachment;filename=downloadname.zip");
OutputStream respOs = response.getOutputStream();
String dldFileName = "SQLLDR_28.txt";
PrintWriter pw1 = new PrintWriter(new FileWriter(dldFileName , false));
BufferedReader readbuffer = new BufferedReader(new FileReader("D:/Sqlldr_Container/downloadFile.txt"));
String strRead;
while((strRead=readbuffer.readLine())!=null){
pw1.println(strRead);
}
pw1.close();
File fil = new File(dldFileName);
ZipUploadStatusFile(dldFileName, respOs);
boolean bool = fil.delete();
System.out.println("-------Temp file Created deleted - "+bool+" ------------");
readbuffer.close();
}
catch (UnAuthenticatedException e) {
e.printStackTrace();
} /*catch (UnAuthorizedAccessException e) {
e.printStackTrace();
}*/ catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void ZipUploadStatusFile(String fileName, OutputStream respOs){
try{
ZipOutputStream out = new ZipOutputStream(respOs);
byte[] data = new byte[1000];
BufferedInputStream in = new BufferedInputStream
(new FileInputStream(fileName));
int count;
out.putNextEntry(new ZipEntry(fileName));
while((count = in.read(data,0,1000)) != -1){
out.write(data, 0, count);
}
in.close();
out.flush();
out.close();
System.out.println("Your file is zipped");
}catch(Exception e){
e.printStackTrace();
}
}
After executing the above method am getting below screen:
Thank you.....
You can't download files by ajax. JavaScript has due to security reasons no facilities to force a Save As dialogue. The best it could do in your particular case is to display the response inline.
Get rid of the <a4j:support> and make it a fullworthy synchronous request by putting the action method straight in the <h:commandButton>.
This is the code that will fulfill the needs of downloading text file in to client system.
public String downloadFileText() {
File file = new File(GlobalPath);
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.setHeader("Content-Disposition", "attachment;filename=file.txt");
response.setContentLength((int) file.length());
ServletOutputStream out = null;
try {
FileInputStream input = new FileInputStream(file);
byte[] buffer = new byte[1024];
out = response.getOutputStream();
int i = 0;
while ((i = input.read(buffer)) != -1) {
out.write(buffer);
out.flush();
}
FacesContext.getCurrentInstance().getResponseComplete();
} catch (IOException err) {
err.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException err) {
err.printStackTrace();
}
}
return null;
}
I dont think that the code will run fine because the code is in JSF MAnaged beans and it is running at server side, so file will be downloaded at the system where application server is running, now what you need to do is to check , use two pcs,
In one pc deploy the web and try to download file from other pc, then check the behaviour of code, if the file could be downloaded in client pc then thats fine other wise you need to find alternatives
Related
Sorry for my poor english but I really want to show two pdf reports from jasper report at the same time in differents tabs on browser. I´m working with java jsf, primefaces. The principal idea is when the button is clicked show this reports in diferents tabs. I try to do this:
I have this in the Managed Bean:
public void showReports() {
RequestContext.getCurrentInstance().execute("document.getElementById('fromGeneral:rep2').click();");
RequestContext.getCurrentInstance().execute("document.getElementById('fromGeneral:rep3').click();");
}
public void printReport(String name) {
try {
Map<String, Object> mapParametros = new HashMap<>();
mapParametros.put("CORR", corr);
printJasper(mapParametros, new File("/Jasper/Reports/" + name));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public void printJasper(Map<String, Object> reportValues, File fileJ) {
ByteArrayInputStream input = null;
BufferedOutputStream output = null;
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
try {
facesContext = FacesContext.getCurrentInstance();
externalContext = facesContext.getExternalContext();
response = (HttpServletResponse) externalContext.getResponse();
FileInputStream file = new FileInputStream(fileJ);
JasperReport compiledTemplate = (JasperReport) JRLoader.loadObject(file);
ByteArrayOutputStream out = new ByteArrayOutputStream();
JasperPrint jasperPrint = JasperFillManager.fillReport(compiledTemplate, reportValues, dataSourceP.getConnection());
JRExporter exporter = new JRPdfExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
exporter.setParameter(JRPdfExporterParameter.PDF_JAVASCRIPT, "this.print();");
exporter.exportReport();
input = new ByteArrayInputStream(out.toByteArray());
response.reset();
response.setHeader("Content-Type", "application/pdf");
response.setHeader("Content-Length", String.valueOf(out.toByteArray().length));
response.setHeader("Content-Disposition", "inline; filename=\"ticket.pdf\"");
output = new BufferedOutputStream(response.getOutputStream(), Constants.DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[Constants.DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
} catch (Exception exception) {
System.out.println(exception.getMessage());
} finally {
try {
if (output != null) {
output.close();
}
if (input != null) {
input.close();
}
} catch (Exception exception) {
/* ... */
}
}
facesContext.responseComplete();
}
An this in my view:
<h:form>
<p:commandButton value="Show them" action="#{reportBean.showReports()}"/>
<p:commandButton value="REPORT 1" id="rep1" style="font-size: 25px; float:right;visibility: hidden;" action="#{reportBean.printReport("Report1")}" ajax="false" onclick="this.form.target = '_blank';"/>
<p:commandButton value="REPORT 2" id="rep2" style="font-size: 25px; float:right;visibility: hidden;" action="#{reportBean.printReport("Report2")}" ajax="false" onclick="this.form.target = '_blank';"/>
</h:form>
But doesn´t work, it just show the second report.
Help!.
Thanks!
Try a hit using p:commandLink like i am using.
<p:commandLink id="PreviewR1" value="Print Preview" ajax="false" action="#{reportBean.printReport("Report1")}" target="_blank" />
<p:commandLink id="PreviewR2" value="Print Preview" ajax="false" action="#{reportBean.printReport("Report2")}" target="_blank" />
It will open the report 1 & 2 in separate browser tab while your original web page will remains the same.
You just don't click the correct buttons:
public void showReports() {
RequestContext.getCurrentInstance().execute("document.getElementById('fromGeneral:rep2').click();");
RequestContext.getCurrentInstance().execute("document.getElementById('fromGeneral:rep3').click();");
}
You're clicking on rep2 and rep3. rep3 doesn't exists, you need to click on rep1 instead. That should be the reason why only the 2nd report is shown.
Finally I found other way to solve it.
The method showReports() instead to click two buttons, this open two xhtml that each one has inside of <h.form> a remotecommand with autorun true, that show the reports. I don´t know if it´s the best way to do it, but It works.
Thanks for all your comments
This question already has answers here:
Why do I have to close the ZipOutputStream in a certain way in this situation?
(2 answers)
Closed 6 years ago.
im trying to implement a download all functionality, my requirement is file should be compressed in .zip, heres the UI
<p:toolbar>
<f:facet name="right">
<p:commandButton value="Download all photos" ajax="false" actionListener="#{ManageActivities.getAllParticipantPhoto}" onclick="PrimeFaces.monitorDownload(start, stop);" icon="ui-icon-image">
<p:fileDownload value="#{ManageActivities.file}" />
</p:commandButton>
</f:facet></p:toolbar>
and here is the managedbean code
private StreamedContent file;
public void getAllParticipantPhoto() {
ByteArrayInputStream bis = new ByteArrayInputStream(zipBytes());
InputStream stream = bis;
file = new DefaultStreamedContent(stream, "zip", "photos.zip");
}
private byte[] zipBytes () {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
try{
for(Participants p : partcpnts){
if(p.getPhoto() != null){
ZipEntry entry = new ZipEntry(p.getFirstName()+".jpg");
zos.putNextEntry(entry);
zos.write(p.getPhoto());
}
}
}catch(Exception e){
e.printStackTrace();
}
return baos.toByteArray();
}
i can download file as ZIP successfully but i am unable to extract it, windows is prompting the'cannot open file as archive' error
changing
file = new DefaultStreamedContent(stream, "zip", "photos.zip");
to
file = new DefaultStreamedContent(stream, "application/zip", "photos.zip", Charsets.UTF_8.name());
fixed it
In my application, I use jsf & richfaces, I want to display a generated pdf in web browser , I have generated this PDF in serverside and it is available in ServletResponse, but I am unable to display it in my web page.
I have tried this question but, it did not solve my problem.
Is there any libraries or special ways to do this?
What I have tried to do is given below.
<h:commandLink rendered="#{ fileImportOptionsViewBean.isFileExist(status.myPdf) }" action="#
{fileImportOptionsViewBean.downloadFile(satus.myPdf)}" target="_blank">
<h:graphicImage url="../../resources/xyz/icons/pdf.png" /></h:commandLink>
downloadFile method
public void downloadFile(String filePath){
try {
File file=new File(filePath);
if(file.exists()){
FacesContext fc=FacesContext.getCurrentInstance();
ExternalContext ec=fc.getExternalContext();
ec.responseReset();
ec.setResponseContentType("application/pdf");
ec.setResponseHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
ec.setResponseBufferSize(8192);
OutputStream output = ec.getResponseOutputStream();
URL url = file.toURL();
try(
BufferedInputStream bis = new BufferedInputStream(url.openStream());
BufferedOutputStream bos = new BufferedOutputStream(output);
){
byte[] buff = new byte[8192];
int bytesRead;
while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
bos.write(buff, 0, bytesRead);
}
}
fc.responseComplete();
}
} catch (Exception e) {
}
}
Any help is appreciated,Thanks.
I don't see anything wrong with your current setup.Most probably the problem lies in your XHTML page and something is causing your h:commandLink not to fire the event.Please refer this post for further details,surely this will be of some help to you.
I have an application, which uses PrimeFaces Mobile to display images.
Sometimes, but not always, the image is not displayed fully - only the top part.
The XHTML code of the page with that image looks like this:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:pm="http://primefaces.org/mobile">
<f:view renderKitId="PRIMEFACES_MOBILE"/>
<h:head>
</h:head>
<f:event listener="#{main.loadFirstImage}" type="preRenderView" />
<h:body id="body">
<pm:page id="page">
<pm:header title="myapp">
</pm:header>
<pm:content id="content">
<h:form>
<p:graphicImage id="image" rendered="false" value="#{main.currentImage()}"
cache="false">
</p:graphicImage>
[...]
</h:form>
</pm:content>
<pm:footer title="m.myapp.com"></pm:footer>
</pm:page>
</h:body>
</html>
And the main bean has following code:
#ManagedBean(name = "main")
#SessionScoped
public class MainView {
private byte[] currentImageData;
private byte[] productId;
private byte[] imageId;
public void loadFirstImage()
{
// This method initializes currentImageData
fetchNextImage();
}
[...]
public StreamedContent currentImage()
{
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
}
else {
return new DefaultStreamedContent(new ByteArrayInputStream(currentImageData));
}
}
[...]
}
How can I fix this error?
Update 1 (03.11.2014 23:21 MSK):
I've tried following to fix the error:
1) Disabling cache for all elements of that Primefaces page.
2) Disabling response chunking by setting maxExtensionSize and maxTrailerSize (server.xml) to -1.
3) Adding a filter with following doFilter:
#Override
public void doFilter(final ServletRequest aServletRequest,
final ServletResponse aServletResponse,
final FilterChain aFilterChain) throws IOException, ServletException {
System.out.println("aServletRequest instanceof HttpServletRequest: " +
(aServletRequest instanceof HttpServletRequest));
if (aServletRequest instanceof HttpServletRequest)
{
final HttpServletRequest request = (HttpServletRequest) aServletRequest;
final String requestURI = request.getRequestURI().toLowerCase();
if (!requestURI.endsWith("/javax.faces.resource/dynamiccontent.properties"))
{
aFilterChain.doFilter(aServletRequest, aServletResponse);
}
}
}
4) Changing the currentImage method to
public StreamedContent currentImage()
{
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
String mimeType = null;
if (imageFileName.toLowerCase().endsWith(".png"))
{
mimeType = "image/png";
}
else if (imageFileName.toLowerCase().endsWith(".jpeg") || imageFileName.toLowerCase().endsWith(".jpg"))
{
mimeType = "image/jpeg";
}
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
return new DefaultStreamedContent(new ByteArrayInputStream(currentImageData), mimeType);
}
}
But it still doesn't work. I wrote a piece of code in another web application and using different framework (Vaadin), which displays images from the same source.
I get the same error (images are displayed only partially).
From this I conclude that the error must occur
when images are retrieved from a particular and/or
when images are saved in MongoDB.
Code for retrieving images from URL
If the error occurs during reading the image, it occurs in the following method:
protected Binary readImage(final String viewItemURL) {
InputStream inputStream = null;
Binary image = null;
try
{
inputStream = new URL(viewItemURL).openStream();;
byte bytes[] = new byte[inputStream.available()];
inputStream.read(bytes);
image = new Binary(bytes);
}
catch (final IOException exception)
{
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
}
return image;
}
viewItemURL is the URL of the image.
Code for saving image in MongoDB
If the problem is with saving images in the database, it occurs in the following method:
protected void saveProductImages(final byte[] aNewProductId, final List<String> aPictureUrls,
final IMongoPersistenceState aPersistenceState) {
final DB db = aPersistenceState.getDb();
final DBCollection productImagesColl = db.getCollection(
MyAppPersistenceAction.COLLECTION_USER_PRODUCT_IMAGES);
for (final String curPictureUrl : aPictureUrls)
{
final Binary imageData = readImage(curPictureUrl);
final Map<String,Object> map = new HashMap<String, Object>();
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_CREATOR_EMAIL, CREATOR_EMAIL);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_PRODUCT_ID, aNewProductId);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_DATA, imageData);
final String fileName = extractFileName(curPictureUrl);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_FILE_NAME, fileName);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_MIME_TYPE, getMimeType(fileName));
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_IS_DELETED, Boolean.FALSE);
productImagesColl.insert(WriteConcern.SAFE, createRecordObject(map));
}
}
Your readImage() method has a major bug:
byte bytes[] = new byte[inputStream.available()];
The InputStream#available() doesn't do what you think it does. It doesn't return the total content length which is what the remainder of the code is expecting. It returns the amount of bytes available for reading without blocking all other threads (i.e. bytes which are currently already put in hardware buffer). This totally explains why you get only that part of the image to display.
No need to be ashamed. Practically all Java starters make the same mistake. The right way to read an InputStream fully is to invoke any read() method on it as long as until it returns -1 indicating EOF (end of file). You can find a bunch of examples and utility library shortcuts in this related question: Convert InputStream to byte array in Java.
Here's a full rewrite of readImage() method doing the right thing, making use of IOUtils which you appear to already have at your hands (and Java 7's try-with-resources with AutoCloseable):
protected Binary readImage(final String viewItemURL) {
try (InputStream inputStream = new URL(viewItemURL).openStream()) {
return new Binary(IOUtils.toByteArray(inputStream));
}
catch (final IOException exception) {
LOGGER.error("", exception);
return null;
}
}
I need to read an Excel file and display its content.
I have a backing bean code which reads a particular Excel file and displays its content in the console. I have to display the contents inside a text editor. Using PrimeFaces I have got the <p:fileUpload> and <p:editor>.
Here's the bean:
public void handleFileUpload(FileUploadEvent event) {
FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public String convertjava(String b) {
try
{
FileInputStream file = new FileInputStream(new File(""));
// Get the workbook instance for XLS file
HSSFWorkbook workbook = new HSSFWorkbook(file);
// Get first sheet from the workbook
HSSFSheet sheet = workbook.getSheetAt(0);
// Iterate through each rows from first sheet
Iterator<Row> rowIterator = sheet.rowIterator();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
// For each row, iterate through each columns
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
switch (cell.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
cell.getBooleanCellValue();
break;
case Cell.CELL_TYPE_NUMERIC:
cell.getNumericCellValue();
break;
case Cell.CELL_TYPE_STRING:
cell.getStringCellValue();
break;
}
}
System.out.println("");
}
file.close();
FileOutputStream out = new FileOutputStream(new File(""));
workbook.write(out);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
System.out.println("error");
}
}
Here's the Facelet:
<h:body>
<h:form enctype="multipart/form-data">
<p:fileUpload fileUploadListener="#{uploadBean.handleFileUpload}"
mode="advanced" update="display" auto="true" sizeLimit="10000000"
allowTypes="/(\.|\/)(xls|xlsx)$/" />
<p:growl id="display" showDetail="true" />
<h:commandButton action="#{uploadBean.convertjava}"
value="Excel Report" />
</h:form>
<br />
</h:body>
Here I am totally blank that how to call that convertJava() method through JSF tags and display the read excel values inside an text editor.
You should get hold of the uploaded file in the file upload listener method. You are currently nowhere doing that. You're basically completely ignoring the uploaded file. This makes indeed no sense.
Assign it as a property of the (view scoped) bean as follows:
private UploadedFile uploadedFile;
public void handleFileUpload(FileUploadEvent event) {
uploadedFile = event.getFile();
// ...
}
Then just feed its InputStream to HSSFWorkbook constructor. You're currently attempting to read a non-existing file. This makes indeed no sense. You should be reading the uploaded file. Replace the nonsensicial
FileInputStream file = new FileInputStream(new File(""));
HSSFWorkbook workbook = new HSSFWorkbook(file);
// ...
by
InputStream input = uploadedFile.getInputStream();
HSSFWorkbook workbook = new HSSFWorkbook(input);
// ...
By the way, inside the loop over the Excel cells, you're also nowhere assigning the found data to a property/variable. All with all, it seems that your root mistake is that you keep ignoring values provided to you instead of assigning them to variables for later reuse/redisplay. This problem is in turn not exactly related to JSF, but just to basic Java. Therefore I recommend to take a JSF pause and make an effort of learning basic Java.