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/
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 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();
}
I've taken over a project where the file upload functionality is broken. Currently when a file is uploaded it is converted to a byteArray like so and then stored in a SQL table
public static byte[] saveAttachment(String filePath) throws IOException{
InputStream inputStream = new FileInputStream(filePath);
byte[] buffer = new byte[1048576];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
while((bytesRead = inputStream.read(buffer)) != -1){
output.write(buffer, 0 , bytesRead);
}
inputStream.close();
return output.toByteArray();
}
I can't say I agree with the approach that has been taken but alas I must work with it. My question becomes how do I go about retrieving this file to display?
I have read
https://wiki.apache.org/tapestry/Tapestry5HowToStreamAnExistingBinaryFile
And tried (which didn't work)
#OnEvent(component="viewAttachment")
private Object viewAttachment(){
final File getFile();
final OutputStreamResponse response = new OutputStreamResponse() {
public String getContentType() {
return "image/jpg";
}
public void prepareResponse(Response response) {
response.setHeader ("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
}
#Override
public void writeToStream(OutputStream out) throws IOException {
try {
InputStream in = new FileInputStream(file);
IOUtils.copy(in,out);
in.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
return response;
}
However I am not sure this is the proper/optimal solution.
Assuming that row.getBytes() returns your image as byte array, and row.getName() is image name:
return new StreamResponse() {
#Override
public String getContentType() {
return "image/jpeg";
}
#Override
public InputStream getStream() throws IOException {
return new ByteArrayInputStream(row.getBytes());
}
#Override
public void prepareResponse(Response response) {
response.setHeader("Content-Disposition", "attachment; filename=\"" + row.getName() + "\"");
}
};
Its better to save the file in a location and save the location in the database. This will help to have size of database.
Also file is available and can retrieve easily without heavy database object.
Or you can add the BLOB column in database and store the file in database.
Convert file into File object
File image = new File("D:\\a.gif");
FileInputStream fis = new FileInputStream(image);
stmt.setBinaryStream(1, fis, (int) image.length());
Add retrieve it using
File image = new File("D:\\java.gif");
FileOutputStream fos = new FileOutputStream(image);
byte[] buffer = new byte[1];
InputStream is = resultSet.getBinaryStream(3);
while (is.read(buffer) > 0) {
fos.write(buffer);
}
fos.close();
this is my file path
public final static String BOOKINGPDFFILE= "D:/Hotels/pdf/";
This below code is what I have written to download pdf from the above resource folder
Pdf="column name in database i used for storing in database"
#RequestMapping(value = "/getpdf/{pdf}", method = RequestMethod.GET)
public void getPdf(#PathVariable("pdf") String fileName, HttpServletResponse response,HttpServletRequest request) throws IOException {
try {
File file = new File(FileConstant.BOOKINGPDFFILE + fileName+ ".pdf");
Files.copy(file.toPath(),response.getOutputStream());
} catch (IOException ex) {
System.out.println("Contract Not Found");
System.out.println(ex.getMessage());
}
}
Here is the way, hope it help.
#RequestMapping(value = "/getpdf/{pdf}", method = RequestMethod.GET)
public void getPdf(#PathVariable("pdf") String fileName, HttpServletResponse response) throws IOException {
try {
File file = new File(FileConstant.BOOKINGPDFFILE + fileName+ ".pdf");
if (file.exists()) {
// here I use Commons IO API to copy this file to the response output stream, I don't know which API you use.
FileUtils.copyFile(file, response.getOutputStream());
// here we define the content of this file to tell the browser how to handle it
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".pdf");
response.flushBuffer();
} else {
System.out.println("Contract Not Found");
}
} catch (IOException exception) {
System.out.println("Contract Not Found");
System.out.println(exception.getMessage());
}
}
You may try something like this:
#RequestMapping(method = { RequestMethod.GET }, value = { "/downloadPdf" })
public ResponseEntity<InputStreamResource> downloadPdf()
{
try
{
File file = new File(BOOKINGPDFFILE);
HttpHeaders respHeaders = new HttpHeaders();
MediaType mediaType = MediaType.parseMediaType("application/pdf");
respHeaders.setContentType(mediaType);
respHeaders.setContentLength(file.length());
respHeaders.setContentDispositionFormData("attachment", file.getName());
InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
}
catch (Exception e)
{
String message = "Errore nel download del file "+idForm+".csv; "+e.getMessage();
logger.error(message, e);
return new ResponseEntity<InputStreamResource>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
And in your web page you can write the link in this way:
download PDF
You need to create an implementation of AbstractPdfView to achieve this.. You can refer this link https://www.mkyong.com/spring-mvc/spring-mvc-export-data-to-pdf-file-via-abstractpdfview/
Here is the Detailed answer for your question.
let me start with the server side code:
Below class is used to create pdf with some random content and return the equivalent byte array outputstream.
public class pdfgen extends AbstractPdfView{
private static ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
public ByteArrayOutputStream showHelp() throws Exception {
Document document = new Document();
// System.IO.MemoryStream ms = new System.IO.MemoryStream();
PdfWriter.getInstance(document,byteArrayOutputStream);
document.open();
document.add(new Paragraph("table"));
document.add(new Paragraph(new Date().toString()));
PdfPTable table=new PdfPTable(2);
PdfPCell cell = new PdfPCell (new Paragraph ("table"));
cell.setColspan (2);
cell.setHorizontalAlignment (Element.ALIGN_CENTER);
cell.setPadding (10.0f);
//cell.setBackgroundColor (new BaseColor (140, 221, 8));
table.addCell(cell);
ArrayList<String[]> row=new ArrayList<String[]>();
String[] data=new String[2];
data[0]="1";
data[1]="2";
String[] data1=new String[2];
data1[0]="3";
data1[1]="4";
row.add(data);
row.add(data1);
for(int i=0;i<row.size();i++) {
String[] cols=row.get(i);
for(int j=0;j<cols.length;j++){
table.addCell(cols[j]);
}
}
document.add(table);
document.close();
return byteArrayOutputStream;
}
}
Then comes the controller code : here the bytearrayoutputstream is converted to bytearray and sent to the client side using the response-entity with appropriate headers.
#RequestMapping(path="/home")
public ResponseEntity<byte[]> render(HttpServletRequest request , HttpServletResponse response) throws IOException
{
pdfgen pg=new pdfgen();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment:filename=report.pdf");
byte[] contents = null;
try {
contents = pg.showHelp().toByteArray();
}
catch (Exception e) {
e.printStackTrace();
}
//These 3 lines are used to write the byte array to pdf file
/*FileOutputStream fos = new FileOutputStream("/Users/naveen-pt2724/desktop/nama.pdf");
fos.write(contents);
fos.close();*/
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/pdf"));
//Here you have to set the actual filename of your pdf
String filename = "output.pdf";
headers.setContentDispositionFormData(filename, filename);
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
ResponseEntity<byte[]> respons = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
return respons;
}
The header should be set to "application/pdf"
Then comes the client side code :
Where you can make ajax request to server to open the pdf file in new tab of the browser
$.ajax({
url:'/PDFgen/home',
method:'POST',
cache:false,
xhrFields: {
responseType: 'blob'
},
success: function(data) {
//alert(data);
let blob = new Blob([data], {type: 'application/pdf'}); //mime type is important here
let link = document.createElement('a'); //create hidden a tag element
let objectURL = window.URL.createObjectURL(blob); //obtain the url for the pdf file
link.href = objectURL; // setting the href property for a tag
link.target = '_blank'; //opens the pdf file in new tab
link.download = "fileName.pdf"; //makes the pdf file download
(document.body || document.documentElement).appendChild(link); //to work in firefox
link.click(); //imitating the click event for opening in new tab
},
error:function(xhr,stats,error){
alert(error);
}
});
Try this
#Controller
#RequestMapping("/download")
public class FileDownloadController
{
#RequestMapping("/pdf/{fileName}")
public void downloadPDFResource( HttpServletRequest request,
HttpServletResponse response,
#PathVariable("fileName") String fileName)
{
//If user is not authorized - he should be thrown out from here itself
//Authorized user will download the file
String dataDirectory = request.getServletContext().getRealPath("/WEB-INF/downloads/pdf/");
Path file = Paths.get(dataDirectory, fileName);
if (Files.exists(file))
{
response.setContentType("application/pdf");
response.addHeader("Content-Disposition", "attachment; filename="+fileName);
try
{
Files.copy(file, response.getOutputStream());
response.getOutputStream().flush();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
I am trying to create a file upload API using Jersey. I would like to obtain details about the upload progress in the server side (is it possible?). Searching the web, the suggestion was to use stream to transfer the file. But... even was described below, the server just to execute the "putFile" method after the file arrives completely. Another problem is that these code only works to small files, when I try a file greater than 40mb
#Path("/file")
public class LargeUpload {
private static final String SERVER_UPLOAD_LOCATION_FOLDER = "/Users/diego/Documents/uploads/";
#PUT
#Path("/upload/{attachmentName}")
#Consumes(MediaType.APPLICATION_OCTET_STREAM)
public Response putFile(#PathParam("attachmentName") String attachmentName,
InputStream fileInputStream) throws Throwable {
String filePath = SERVER_UPLOAD_LOCATION_FOLDER + attachmentName;
saveFile(fileInputStream, filePath);
String output = "File saved to server location : ";
return Response.status(200).entity(output).build();
}
// save uploaded file to a defined location on the server
private void saveFile(InputStream uploadedInputStream, String serverLocation) {
try {
OutputStream outpuStream = new FileOutputStream(new File(
serverLocation));
int read = 0;
byte[] bytes = new byte[1024];
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
outpuStream.write(bytes, 0, read);
}
outpuStream.flush();
outpuStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws FileNotFoundException {
ClientConfig config = new ClientConfig();
config.property(ClientProperties.CHUNKED_ENCODING_SIZE, 1024);
Client client = ClientBuilder.newClient(config);
File fileName = new File("/Users/diego/Movies/ff.mp4");
InputStream fileInStream = new FileInputStream(fileName);
String sContentDisposition = "attachment; filename=\"" + fileName.getName()+"\"";
Response response = client.target("http://localhost:8080").path("upload-controller/webapi/file/upload/"+fileName.getName()).
request(MediaType.APPLICATION_OCTET_STREAM).header("Content-Disposition", sContentDisposition).
put(Entity.entity(fileInStream, MediaType.APPLICATION_OCTET_STREAM));
System.out.println(response);
}