Converting HTML to proper Excel File - java

I currently create xls files by outputting an HTML table with the proper header and file extension. Here is the sample code:
String tabledata = "<table>MORE TABLE HTML HERE</table>";
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\"somefile.xls\"");
out.println(tabledata);
This works great except you get an error before opening "The file format and extension of 'somefile.xls' don't match." Once opened, it looks exactly how I want it.
I used Apache POI elsewhere, so figured I could try using this, but I don't want to have to build all elements in some long script looking for rows, columns and different styles. I was thinking that I could convert the HTML to an InputStream and then create the Workbook, but it doesn't like the headers. Here is the code:
InputStream is = new ByteArrayInputStream(tabledata.getBytes("UTF-8"));
HSSFWorkbook wb = new HSSFWorkbook(is);
FileOutputStream fileOut = new FileOutputStream("somefile.xls");
wb.write(fileOut);
fileOut.close();
Is something like this possible if the headers were added/changed? If so, how would I modify this code to work properly?

Related

Apache POI Clone Sheet corrupting the excel file

I have an excel template file I am retrieving from minIO, I perform some writing operation on this excel and I finally return the modified file to the user calling my code.
This flow was working fine until I tried to clone one of the sheet of my excel.
When I do that and I try to open it with Excel the file looks to be corrupted and Excel won't open it.
I am a bit lost, I am not sure what could cause this behaviour. I tried to clone an empty sheet I created for testing and it was working, so it might be related to the content of the sheet I am trying to clone but I have no idea as everything runs fine in the code.
So, theses are the part I consider relevants (getting the file from minIO, the moment I clone the sheet and finally when I write to a ByteArray)
try (InputStream inputStream = minioClient.getObject(
GetObjectArgs.builder()
.bucket("someBucket")
.object("someObject.xlsx")
.build()
)) {
Workbook workbook = new XSSFWorkbook(inputStream);
...
Sheet newSheet = workbook.cloneSheet(workbook.getSheetIndex(sheetTemplate));
workbook.setSheetName(workbook.getSheetIndex(newSheet.getSheetName()), "newName");
workbook.setSheetOrder("newName", workbook.getSheetIndex(sheetTemplate));
newSheet.getRow(10).getCell(2).setCellValue("someValue");
...
ByteArrayOutputStream bos = new ByteArrayOutputStream();
workbook.write(bos);
workbook.close();
return Optional.of(bos.toByteArray());
}
I know the question is pretty vague but maybe there is something in the way I handle this flow that it's incorrect although everything worked fine before I tried to clone some of the sheet of our template.
Any pointer would be highly appreciated.
Thank you in advance.

Excel download not working after populating the values in java

In my application using spring and angularjs and java, On clicking a button ,there is an ajax call which fetches the data from db and the data needs to be written to an excel file and the same file needs to be downloaded in the browser itself. I am attaching the code snippet for the same .
Now the problem is, even though the data is being fetched and I am able to bind it as worksheet using poi , the excel file never comes in the browser as download.
kindly help me in finding a right solution. Thank You.
fileName.append(Calendar.get(Calendar.SECOND));
fileName.append(oCalendar.get(Calendar.MILLISECOND));
Sheet sheet = workbook.createSheet("Transaction" + fileName.toString());
CellStyle style = workbook.createCellStyle();
style.setFont(font);
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("Name");
header.createCell(1).setCellValue("ACC");
header.createCell(2).setCellValue("Date");
header.createCell(0).setCellValue("TRANSACTION_RECONCILIATION_IDENTIFIER");
header.createCell(1).setCellValue("ORIGINAL_RECONCILIATION_IDENTIFIER");
header.createCell(2).setCellValue("STR_TRANSACTION_Date");
response.setHeader("Content-Disposition", "attachment; filename=\"TransactionDetails.xls\"");
OutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
After writing the output stream you should use
response.flushBuffer();
Looks like you're missing the contentType definition. Before calling the write() method try setting the contentType like this:
response.setContentType("application/octet-stream");
This should tell the browser that a download is expected from the server. A relevant question was asked here: response.setContentType("APPLICATION/OCTET-STREAM")
In my code I write like this:
response.setContentType("application/octet-stream");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Content-Disposition",
"attachment; filename=TransactionDetails.xls");
workbook.write(response.getOutputStream());
Hope this helps

How do I force download an excel file?

I am using Grails.
I have a sample code to download an excel file:
XSSFWorkbook workbook = new XSSFWorkbook()
....
FileOutputStream out = new FileOutputStream(new File("C:\\excel.xlsx"))
workbook.write(out)
out.close()
Here the excel file will be downloaded automatically. I would want system to prompt the user to download the file in the browser window.
I tried using the below code:
response.setHeader("Cache-Control", "public")
response.setContentType("application/vnd.ms-excel")
response.setHeader('Content-Disposition', 'Attachment;Filename="excel.xlsx"')
ServletOutputStream outputStream = response.getOutputStream()
workbook.write(outputStream)
outputStream.flush()
outputStream.close()
Which doesn't work. How to achieve this?
Thanks in advance.
Quoted form W3C
Parameter values are normally case sensitive, but certain parameters are interpreted to be case- insensitive, depending on the intended use. (For example, multipart boundaries are case-sensitive, but the "access- type" for message/External-body is not case-sensitive.)
There for, try changing
response.setHeader('Content-Disposition', 'Attachment;Filename="excel.xlsx"')
to
response.setHeader('Content-Disposition', 'attachment;filename="excel.xlsx"')

Logging results to an excel file (apache poi), error if I open the file while program is still running

I have a program that does various tasks and then logs the results to an excel file. I'm using Apache POI.
The program is working perfectly and is logging everything as I want it. However, it can take hours to complete, and I noticed that if I open the excel file while it's still running, it fails and throws a java.io.FileNotFoundException exception with this message (The process cannot access the file because it is being used by another process) when it tries to save to the file.
My guess is that by opening the excel file, the program is getting locked out of writing to it. How can I get around this? Is there a way to lock users out of opening the file while the program runs (Forcing them to access it as read-only)?
This is the code that gets used to initially create the file:
HSSFWorkbook wb = new HSSFWorkbook();
//.. bunch of POI stuff here
FileOutputStream fileOut = new FileOutputStream("C:\\ file path here");
wb.write(fileOut);
wb.close();
fileOut.close();
And then in a separate logResults() method, the file is accessed and saved:
FileInputStream file = new FileInputStream(new File("C:\\ file path here"));
HSSFWorkbook wb = new HSSFWorkbook(file);
//.. bunch more POI stuff here
FileOutputStream fileOut = new FileOutputStream("C:\\ file path here");
wb.write(fileOut);
wb.close();
fileOut.close();
I don't think you can do anything in Java side.
You may need do something in Excel file as follows
Private Sub Workbook_Open()
If ThisWorkbook.ReadOnly
Then
MsgBox "File already in use"
ThisWorkbook.Close
savechanges:=False
End If
End Sub
'This is workbook event code.
'To input this code, right click on the Excel icon on the worksheet
'(or next to the File menu if you maximise your workbooks),
'select View Code from the menu, and paste the code
I found a work around. I'm not sure if it's the most elegant solution, but it seems to work well enough.
When the file is created, I set it to read only with. Then every time I will log a result, I switch it back to writeable, and then back to read only after it's saved.
Basically something like this:
File file = new File(filePath);
//..
file.setWritable(true);
FileOutputStream fileOut = new FileOutputStream(filePath);
file.setReadOnly();

Apache poi excel file throws confirmation before closing

I am using Apache poi for generating excel data.It works fine for all cell types except formula type cell.
The excel file with formula type cell when closed even without any changes throws a confirmatiorn like this.
For XLS fomat
http://i40.tinypic.com/126d9uw.jpg
For XLSX format:
http://i40.tinypic.com/126d9uw.jpg
Is there any way to suppress this confirmation.
I tried the below code but it didnt help.
//Workbook wb = WorkbookFactory.create(new FileInputStream(absolutexlsFileName));
FileInputStream fis = new FileInputStream(absolutexlsFileName);
Workbook wb = new XSSFWorkbook(fis);
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
evaluator.evaluateAll();
OutputStream out = msg.getHttpServletResponse().getOutputStream();
msg.getHttpServletResponse().setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
msg.getHttpServletResponse().setHeader("Expires:", "0"); // eliminates browser caching
msg.getHttpServletResponse().setHeader("Content-Disposition", "attachment; filename="+absolutexlsFileName);
wb.write(out);
out.flush();
out.close();
Looks like your formula changes would cause a cell update somewhere but you don't calculate it (but excel does and thus the change confirmation). You have to evaluate your formulas in order to prevent that warning [1]
[1] http://poi.apache.org/spreadsheet/eval.html

Categories