I have a web service app in Java and I'm trying to do an export functionality to export some data from the database to an excel file
For this I'm using HttpServletResponse, but even I set up a filename and a encoding type, the file exported is not using those.
I need to set up the name of the file with the corresponding export date and the encoding type to allow UTF-8 characters like á,ó,ñ, etc --> This was fixed, see Edit 1 below.
Below you have my code:
#RequestMapping(value = "/export", method = RequestMethod.GET)
public #ResponseBody
void export(HttpServletRequest request, HttpServletResponse r) {
Response response = new Response();
try {
response = service.export();
if(response.isSuccess()){
r.setHeader( "Content-Disposition","attachment; filename=export_20171216.xls");
r.setContentType("application/vnd.ms-excel");
r.setCharacterEncoding("UTF-8");
OutputStream out = r.getOutputStream();
byte[] buffer = new byte[4096];
int length;
while ((length = ((InputStream) response.getData()).read(buffer)) > 0){
out.write(buffer, 0, length);
}
out.flush();
out.close();
}
else{
r.sendError(801, response.toString());
}
} catch (Exception e) {
e.printStackTrace();;
}
}
As the result, I'm getting files with the name like 2ea4a24e-b0b4-4d50-9604-4fcdb3713b90.xls and inside the file words like: Número instead of Número
--- Edit 1
I fixed the stress vowels with the follwing code when creating the ByteArray
new ByteArrayInputStream(sb.toString().getBytes("ISO-8859-15"));
If I got your issue correctly you are trying to keep filenames with symbols that have to be encoded. According setHeaders method docs:
the header value If it contains octet string, it should be
* encoded according to RFC 2047
* (http://www.ietf.org/rfc/rfc2047.txt)
And more likely your input filenames are in ASCII that are octets. Try to use java.nio.charset.CharsetDecoder with appropriate decoding when you set header with your fancy symbols.
A bit more explanations: ISO-8859-15 is not Unicode format and any symbol above of it leads to encoding the whole string for HTTP attributes.
public static void sendResponse (InputStream inputData, String fileName, HttpServletResponse res)
throws IOException {
try {
String contenttype = new ConfigurableMimeFileTypeMap().getContentType(fileName);
res.reset();
res.setContentType(contenttype);
res.addHeader("Content-Disposition", String.format("attachment;filename=\"%s\"", name));
ByteStreams.copy(inputData, res.getOutputStream());
} catch (Exception e) {
throw new IOException(e);
}
}
Please try with this:-I have used this in my code it works..
Let me know if still problem perisists
public void downloadFile(String fileName, String paramName,
HttpServletResponse response) {
File fileToBeDownloaded = null;
InputStream fileInputStream = null;
ServletOutputStream servletOutputStream;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
response.addHeader("Content-Disposition", "attachment; filename=" +
fileName);
servletOutputStream = response.getOutputStream();
IOUtil.copyCompletely(fileInputStream, servletOutputStream);
servletOutputStream.flush();
servletOutputStream.close();
}
Related
I am trying to use a Spring Boot RestController to download multiple pdf files.But for some reason only the first file is downloaded.The program does not throw any error.Not sure what the issue is.Is Multipart needed for this?
#RequestMapping(value = "downloadAgain", method = RequestMethod.GET)
#ResponseBody
public void newRun(HttpServletResponse response) {
String fileName1="pdf1.pdf";
String fullName1="C://Users//pdf1.pdf";
newDownloadRun(response,fileName1,fullName1);
String fileName2="pdf2.pdf";
String fullName2="C://Users//pdf2.pdf";
newDownloadRun(response,fileName2,fullName2);
}
public void newDownloadRun(HttpServletResponse response,String fileName,String fullName) {
response.setContentType("application/pdf");
response.setHeader( "Content-Disposition", "attachment;filename="+ fileName );
response.setHeader("Content-disposition", "attachment; filename=" + fileName);
try {
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
FileInputStream fis = new FileInputStream(fullName);
int len;
byte[] buf = new byte[1024];
while((len=fis.read(buf))> 0) {
bos.write(buf,0,len);
}
bos.close();
response.flushBuffer();
}catch(Exception ex) {
ex.printStackTrace();
}
}
Http protocol designed to send one file per request. if you want to send multiple files you need to prepare it as multipart/related. Look into this article https://www.motobit.com/tips/detpg_multiple-files-one-request/
I have a file txt on the server (previously generated). When user clicks on button it generates the file, now I want (additionally) download the file inside my function. But I can't make it work(I'm new on JAVA EE), cause I don't know how to get HttpServletResponse.
From web I call function with this:
#Path("getreport")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public JSONObject getreport(CommonInput input) {
JSONObject j = objectmapper.conertValue(reportBean.getreport(),JSONObject.class);
return j;
}
reprotBean has function:
public void getreport() {
//...doing many things
//generating my file
List<String> lines = new ArrayList<>();
lines.add("star file");
//..adding many lines
Path file = Paths.get("C:\\Users\\myuser\\file.txt");
Files.write(file, lines, StandardCharsets.UTF_8);
downloadFile();
//...doing many things
}
I found this way to download my file:
public void downloadFile(HttpServletResponse response){
String sourceFile = ""C:\\Users\\myuser\\file.txt"";
try {
FileInputStream inputStream = new FileInputStream(sourceFile);
String disposition = "attachment; fileName=outputfile.txt";
response.setContentType("text/txt");
response.setHeader("Content-Disposition", disposition);
response.setHeader("content-Length", String.valueOf(stream(inputStream, response.getOutputStream())));
} catch (IOException e) {
logger.error("Error occurred while downloading file {}",e);
}
}
private long stream(InputStream input, OutputStream output) throws IOException {
try (ReadableByteChannel inputChannel = Channels.newChannel(input); WritableByteChannel outputChannel = Channels.newChannel(output)) {
ByteBuffer buffer = ByteBuffer.allocate(10240);
long size = 0;
while (inputChannel.read(buffer) != -1) {
buffer.flip();
size += outputChannel.write(buffer);
buffer.clear();
}
return size;
}
}
When I try to use downloadFile(), it requires HttpServletResponse, and I don't have that parameter. I can't understand how to get that (how it works), or do I have to use another method for download my file?
All solutions I found requires HttpServletResponse (download files from browsers)
If you have that file generated already. Just need write it to HttpServletResponse
resp.setContentType("text/plain");
resp.setHeader("Content-disposition", "attachment; filename=sample.txt");
try(InputStream in = req.getServletContext().getResourceAsStream("sample.txt");
OutputStream out = resp.getOutputStream()) {
byte[] buffer = new byte[ARBITARY_SIZE];
int numBytesRead;
while ((numBytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, numBytesRead);
}
}
Be sure to make your file to be accessed by ServeletContext
If you are using Spring Rest framework. Can refer to below
#GetMapping("/download")
public ResponseEntity<byte[]> downloadErrorData() throws Exception {
List<Employee> employees = employeeService.getEmployees();
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(employees);
byte[] isr = json.getBytes();
String fileName = "employees.json";
HttpHeaders respHeaders = new HttpHeaders();
respHeaders.setContentLength(isr.length);
respHeaders.setContentType(new MediaType("text", "json"));
respHeaders.setCacheControl("must-revalidate, post-check=0, pre-check=0");
respHeaders.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
return new ResponseEntity<byte[]>(isr, respHeaders, HttpStatus.OK);
}
credit to: https://www.jeejava.com/file-download-example-using-spring-rest-controller/
i have implemented a servlet to download doc files available under my application classpath.
what happening is; file is downloading but ms-word is unable to open it property.
see the screenshot of ms-word:
Servlet implementation is as follows:
public class DownloadFileServlet extends HttpServlet {
protected void doGet(
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String fileName = "test.doc";
ClassPathResource resource = new ClassPathResource(File.separator + fileName);
ServletOutputStream sos = null;
FileInputStream fis = null;
try {
response.setContentType("application/msword");
response.setHeader("Content-disposition", "attachment; fileName=\"" + fileName + "\"" );
fis = new FileInputStream(new File(resource.getURI().getPath()));
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(fis);
sos = response.getOutputStream();
sos.write(bytes);
sos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if( fis != null) {
fis.close();
}
if( sos != null) {
sos.close();
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
i have tried almost all suggested Content Types for ms-word files. but still it is not working.
application/msword
application/ms-word
application/vnd.ms-word
Kindly suggest I'm making a mistake or is there any other way to achieve.
Note: i have tried almost all approaches available on SO.
Instead of reading, converting to byte[] simply write directly to the OutputStream. You shouldn't close the OutputStream as that is being handled by the container for you.
I would rewrite your servlet method to more or less the following (also why is it a servlet and not a (#)Controller?
protected void doGet(
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String fileName = "test.doc";
ClassPathResource resource = new ClassPathResource(File.separator + fileName);
InputStream input = resource.getInputStream();
try {
response.setContentType("application/msword");
response.setHeader("Content-disposition", "attachment; fileName=\"" + fileName + "\"" );
org.springframework.util.StreamUtils.copy(input, response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOEXception ie) {}
}
}
}
i do not know what a ClassPathResource class does. hence modified the code a bit.
ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
InputStream is = clsLoader.getResourceAsStream("test.doc");
and in the try block use:
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(is);
this should work fine. i placed the doc in the classpath. modify it to suit your needs.
Regarding the mime mapping, open your server properties and you will find a list of mime mapping. Eg. in eclipse for tomcat, just double click on the server and you should be able to find the mime mapping list there. application/msword worked fine
I am doing a JSP site, where I need to display PDF files.
I have byte array of PDF file by webservice and I need to display that byte array as PDF file in HTML. My question is how to covert that byte array as PDF and display that PDF in new tab.
save these bytes on the disk by using output stream.
FileOutputStream fos = new FileOutputStream(new File(latest.pdf));
//create an object of BufferedOutputStream
bos = new BufferedOutputStream(fos);
byte[] pdfContent = //your bytes[]
bos.write(pdfContent);
Then send its link to client side to be opened from there.
like http://myexamply.com/files/latest.pdf
better is to use a servlet for this, since you do not want to present some html, but you want to stream an byte[]:
public class PdfStreamingServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doGet(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException,
IOException {
processRequest(request, response);
}
public void processRequest(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException,
IOException {
// fetch pdf
byte[] pdf = new byte[] {}; // Load PDF byte[] into here
if (pdf != null) {
String contentType = "application/pdf";
byte[] ba1 = new byte[1024];
String fileName = "pdffile.pdf";
// set pdf content
response.setContentType("application/pdf");
// if you want to download instead of opening inline
// response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
// write the content to the output stream
BufferedOutputStream fos1 = new BufferedOutputStream(
response.getOutputStream());
fos1.write(ba1);
fos1.flush();
fos1.close();
}
}
}
Sadly, you do not tell us what technology you use.
With Spring MVC, use #ResponseBody as an annotation for your controller method and simply return the bytes like so:
#ResponseBody
#RequestMapping(value = "/pdf/shopping-list.pdf", produces = "application/pdf", method=RequestMethod.POST)
public byte[] downloadShoppingListPdf() {
return new byte[0];
}
Opening in a new tab is an unrelated matter that has to be handled in the HTML.
I have a servlet which just read a file and send it to the browser.
The file is readen correctly, but on OutputStream.flush(), the browser receive no data.
Firefox says :
"Corrupted Content Error
The page you are trying to view cannot be shown because an error in the data transmission was detected.". Firebug shows the status "Aborted".
IE open or save an empty file.
I tried little or big files.
The code is :
/**
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* #param request servlet request
* #param response servlet response
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Use a ServletOutputStream because we may pass binary information
response.reset();
OutputStream out = response.getOutputStream();
// Get the file to view
String file = request.getParameter("path");
// Get and set the type and size of the file
String contentType = getServletContext().getMimeType(file);
response.setContentType(contentType);
long fileSize = (new File(file)).length();
response.setHeader("Content-Length:", "" + fileSize);
File f = new File(file);
response.setHeader("Content-Disposition", "attachment;filename="+f.getName());
response.setContentLength((int) fileSize);
// Return the file
try {
returnFile(file, out, response);
} catch (Exception e) {
Logger.getLogger(AffichageItemsServlet.class).error("", e);
} finally {
out.close();
}
}
// Send the contents of the file to the output stream
public static void returnFile(String filename, OutputStream out, HttpServletResponse resp)
throws FileNotFoundException, IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(filename);
byte[] buff = new byte[8* 1024];
int nbRead = 0;
while ((nbRead = fis.read(buff, 0, buff.length)) !=-1) {
out.write(buff, 0, nbRead);
}
out.flush();
} finally {
if (fis != null) {
fis.close();
}
}
}
The response is sent on "out.flush".
Any idea ?
For one thing, remove this line (you call setContentLength() below that):
response.setHeader("Content-Length:", "" + fileSize);
Also, you might try moving the getOutputStream() call to just before you start using the stream.