How to send PDF file on response - java

I'm trying to write a web app that converts images to PDF file. The user sends a couple of images (JPEG, PNG) and should receive and download a PDF file.
The main problem, for now, is that I don't know how to return the PDF file back to the client.
Here is my controller:
#PostMapping(path = "/upload",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void uploadFiles(#RequestParam("files") MultipartFile[] files) throws IOException {
imageToPdfConversionService.convert(files);
}
This is the service that converts images to PDF file (here I'm using itextpdf library):
public void convert(MultipartFile[] files) throws IOException {
List<ImageData> imagesData = Arrays.stream(files)
.map(file -> {
try {
return ImageDataFactory.create(file.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
// PdfDocument pdfDocument = new PdfDocument(new PdfWriter("ImageToPdf.pdf"));
FileOutputStream fileOutputStream = new FileOutputStream("letspdf-server/src/main/resources/documents/file.pdf");
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(fileOutputStream));
Document document = new Document(pdfDocument);
for (ImageData image : imagesData) {
Image img = new Image(image);
img.setWidth(pdfDocument.getDefaultPageSize().getWidth() - 50);
img.setAutoScaleHeight(true);
document.add(img);
pdfDocument.addNewPage();
}
pdfDocument.close();
}
Also, maybe store a PDF file somewhere and create a 'Download' button on the client-side when a file is generated to download the file from storage?

So first of all you need to change your api to return ResponseEntity and convert your resulted pdf into byte array. I'll attach a code snippet as an example
public static ResponseEntity<Resource> makeResponse(byte[] file, String filename, MultiValueMap<String, String> customHeaders) {
MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
HttpHeaders headers = new HttpHeaders();
if (StringUtils.isNotEmpty(filename)) {
try {
mediaType = MediaType.valueOf(MIME_TYPES.detect(filename));
} catch (Exception var6) {
}
ContentDisposition contentDisposition = ContentDisposition.builder("attachment").filename(filename, StandardCharsets.UTF_8).build();
headers.setAccessControlExposeHeaders(ACCESS_CONTROL_EXPOSE_HEADERS);
headers.setContentDisposition(contentDisposition);
}
if (customHeaders != null && !customHeaders.isEmpty()) {
headers.addAll(customHeaders);
}
ByteArrayResource body = null;
if (file != null) {
body = new ByteArrayResource(file);
}
return ((BodyBuilder)ResponseEntity.ok().headers(headers)).contentType(mediaType).body(body);
}

Related

Spring REST for zip file download

I'm using the following REST method to be called from the UI to download the ZIP archive:
#RequstMapping("/download")
public void downloadFiles(HttpServletResponse response) {
response.setStatus(HttpServletResponse.SC_OK);
try {
downloadZip(response.getOutputStream());
} catch (IOException e) {
throw new RuntimeException("Unable to download file");
}
}
private void downloadZip(OutputStream output) {
try (ZipOutputStream zos = new ZipOutputStream(outputStream)) {
byte[] bytes = getBytes();
zos.write(bytes);
zos.closeEntry();
} catch (Exception e) {
throw new RuntimeException("Error on zip creation");
}
}
It's working fine, but I wanted to make the code more Spring oriented, e.g. to return ResponceEntity<Resource> instead of using ServletOutputStream of Servlet API.
The problem is that I couldn't find a way to create Spring resource from the ZipOutputStream.
Here is a way to return bytestream, you can use it to return zip file as well by setting content-type.
#RequestMapping(value = "/download", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Resource> download() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
InputStream is = null; // get your input stream here
Resource resource = new InputStreamResource(is);
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}

How can i download the PDF file in spring mvc?

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();
}
}
}
}

how to convert .doc .docx using tika apache?

i want ask to convert doc docx to file text in here code
enter code here
public DokumenExtractor(String filename) {
context = new ParseContext();
detector = new DefaultDetector();
parser = new AutoDetectParser(detector);
context.set(Parser.class, parser);
outputstream = new ByteArrayOutputStream();
metadata = new Metadata();
try {
process(filename);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void process(String filename) throws Exception {
URL url;
File file = new File(filename);
if (file.isFile()) {
url = file.toURI().toURL();
this.PathFile=(file.getPath()).toString();
} else {
url = new URL(filename);
}
this.input = TikaInputStream.get(url, metadata);
ContentHandler handler = new BodyContentHandler(outputstream);
parser.parse(input, handler, metadata, context);
input.close();
}
but output like this
PAGE * MERGEFORMAT 36
not content of document clean ??? how to remove format Page after get string from document

Sending a Zip file to Rest WebService

I'm trying to implement a method in my java based application that involves uploading a zip file to my server. Client is java, server is java (REST , jboss 7) . In the past I successfully managed to upload image files, but now, with a zip file i am having issues and my main doubt is if these issues are client related or server related (or both) .
So , my client looks like this
final HttpHeaders headers = HttpClientUtils.headersJSONAndAcceptJSON();
MultiValueMap<String, Object> requestMap = new LinkedMultiValueMap<String, Object>();
addMap("filename", filename, requestMap);
addMap("contenttype", contentType, requestMap);
addMap("type", type, requestMap);
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
int b = -1;
//file data is the inputstream created from the File
while ( (b = filedata.read())>= 0 ) {
bout.write(b);
}
ByteArrayResource rs = new ByteArrayResource( bout.toByteArray() ){
#Override
public String getFilename() {
return "";
}
};
addMap("resource", rs, requestMap);
} catch (IOException e1) {
throw new IllegalStateException("Error");
}
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.setAccept(Arrays.asList(HttpClientUtils.mtypeJSONUtf8()));
final String url = this.baseURL + summaryURL;
try {
ResponseEntity<Summary> rEntity = restTemplate.exchange(
url,
HttpMethod.POST,
HttpClientUtils.entity(headers, requestMap),
Summary.class
(...)
and meanwhile on the server side I have
#POST
#Path("/")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("application/json; charset=UTF-8")
public Summary addImportedSummary(#MultipartForm FileUploadFormObj imp)
{
Summary importedSummary = new Summary();
Map<String , String> newpath = new HashMap<String, String>();
if(imp.getFileData() != null)
{
ZipInputStream zip = new ZipInputStream(imp.getFileData());
ZipEntry entry;
try {
while ((entry = zip.getNextEntry()) != null)
{
if(entry.getName().endsWith(".html") || entry.getName().endsWith(".htm"))
{
if(entry.getSize() > 0)
{
StringWriter writer = new StringWriter();
IOUtils.copy(zip, writer, "UTF-8");
String content = writer.toString();
//do something with the content
}
}
}
zip.close();
} catch (IOException e) {
throw new BadRequestException("Error " + e);
}
}
The problem happens when I try to copy the file content with IOUtils or any other reader. I always get the exception
ZipException too many length or distance symbols
Now, I think the problem might be in the way I am sending the data due to the file being a zip but I don't know exactly where the problem is. Did everyone ever ran into a similar problem?

iText – HTML to PDF - Image is not displayed in PDF

I have a html page with text, image and I am parsing the HTML content to iText to generate the PDF. In the generated PDF,Included images are not getting displayed and , only the text is getting displayed.
If I pass the absolute path like D:/Deiva/CRs/HTMLPage/article-101-horz.jpg then the image will get printed. But if I try to print the image from the server like
http://localhost:8085/content/dam/article-101-h1.jpg or http://www.google.co.in/intl/en_ALL/images/logos/images_logo_lg.gif
then it is not getting printed in the PDF.
NOTE: I am using itextpdf-5.2.1.jar to generate the PDF.
My HTML Code (Article.html):
<html>
<head>
</head>
<body>
<p>Generate PDF with image using iText.</p>
<img src="http://localhost:8085/content/dam/article-10-h1.jpg"></img>
<img src="http://www.google.co.in/intl/en_ALL/images/logos/imgs_logo_lg.gif"></img>
<img class="right horz" src="D:/Deiva/CRs/HTMLPage/article-101-horz.jpg"></img>
</body>
</html>
I am using the below java code for generating the PDF:
private void createPDF (){
String path = "D:/Deiva/Test.pdf";
PdfWriter pdfWriter = null;
//create a new document
Document document = new Document();
try {
//get Instance of the PDFWriter
pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(path));
//document header attributes
document.addAuthor("betterThanZero");
document.addCreationDate();
document.addProducer();
document.addCreator("MySampleCode.com");
document.addTitle("Demo for iText XMLWorker");
document.setPageSize(PageSize.LETTER);
//open document
document.open();
InputStream is = new FileInputStream("D:/Deiva/CRs/Oncology/Phase5/CR1/HTMLPage/Article.html");
// create new input stream reader
InputStreamReader isr = new InputStreamReader(is);
//get the XMLWorkerHelper Instance
XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
//convert to PDF
worker.parseXHtml(pdfWriter, document, isr);
//close the document
document.close();
//close the writer
pdfWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Please suggest a solution to display the image in PDF.
Thanks in advance.
Deiva
I think you can do it easily using a Servlet for viewing the image. How to write a servlet for this is here
Here a sample dispatcher for you. Just edit the required places as needed
#Controller
public class ImageController extends DispatcherServlet {
private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.
// Properties ---------------------------------------------------------------------------------
private String imagePath;
#RequestMapping(value="images/{imageId:.+}", method = RequestMethod.GET)
public #ResponseBody void getImage(#PathVariable String imageId,HttpServletRequest request, HttpServletResponse response){
String requestedImage = request.getPathInfo();
this.imagePath ="image path in server here";
if (requestedImage == null) {
// Do your thing if the image is not supplied to the request URI.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}catch(IOException ioException){
logger.error("error image path incorrect:{}", ioException);
} // 404.
return;
}
File image=null;
try {
image = new File(imagePath, URLDecoder.decode(imageId, "UTF-8"));
} catch (UnsupportedEncodingException unsupportedEncodingException) {
logger.error("error image can not decode:{}", unsupportedEncodingException);
}
// Check if file actually exists in filesystem.
if (!image.exists()) {
// Do your thing if the file appears to be non-existing.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}catch(IOException ioException){
logger.error("error image does not exists:{}", ioException);
} // 404.
return;
}
// Get content type by filename.
String contentType = "jpeg";
contentType="image/"+contentType;
// Init servlet response.
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(image.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");
// Prepare streams.
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
// Open streams.
try {
input = new BufferedInputStream(new FileInputStream(image), DEFAULT_BUFFER_SIZE);
} catch (FileNotFoundException e) {
logger.error("error creating file input stream to the image file :{}", e);
}
try {
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
} catch (IOException e) {
logger.error("error creating output stream to the http response :{}", e);
}
// Write file contents to response.
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
try {
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} catch (IOException e) {
logger.error("error writing the image file to outputstream :{}", e);
}
} finally {
// Gently close streams.
close(output);
close(input);
}
}
// Helpers (can be refactored to public utility class) ----------------------------------------
private void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
// Do your thing with the exception. Print it, log it or mail it.
logger.error("error closing resources:{}", e);
}
}
}
}
Here are some examples: https://developers.itextpdf.com/examples/xml-worker-itext5/html-images
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() { return "src/main/resources/html/"; }
});
If the HTML file you're parsing is stored in a directory that is different from the working directory, iText won't be able to create Image objects. We have to supply an implementation of the ImageProvider interface that tells iText what to do if an img tag is encountered. This interface has the following methods:
Image retrieve(final String src);
String getImageRootPath();
void store(String src, Image img);
void reset();
You can write your own class implementing these four methods, or you can subclass AbstractImageProvider. It is preferred to do the latter. XML Worker will use the store() method of the AbstractImageProvider class to cache all the Image objects that are encountered in a Map. These objects will be reused when the retrieve() method is called for an image with the same src. If you don't cache images, your PDF will be bloated. The same image bits and bytes will be written to the PDF more than once. The reset() method clears the cache; it is used when an ImageProvider is cloned. Finally, the getImageRootPath() method isn't implemented.
If the HTML file you're parsing is stored in a directory that is different from the working directory, iText won't be able to create Image objects. We have to supply an implementation of the ImageProvider interface that tells iText what to do if an img tag is encountered. This interface has the following methods:
You can write your own class implementing these four methods, or you can subclass AbstractImageProvider. It is preferred to do the latter. XML Worker will use the store() method of the AbstractImageProvider class to cache all the Image objects that are encountered in a Map. These objects will be reused when the retrieve() method is called for an image with the same src. If you don't cache images, your PDF will be bloated. The same image bits and bytes will be written to the PDF more than once. The reset() method clears the cache; it is used when an ImageProvider is cloned. Finally, the getImageRootPath() method isn't implemented. You have to implement it yourself, as is done in the following snippet:
to show image with Itext, you have to Changing the default configuration about Image Provider Like it :
i do it from http://demo.itextsupport.com/xmlworker/itextdoc/flatsite.html
public class HtmlToPDF1 {
public static void main(String ... args ) throws DocumentException, IOException {
FontFactory.registerDirectories();
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream("src/test/ressources/mypdf.pdf"));
document.open(); HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() {
return "/home/fallphenix/workspace/JAVA/JEE/testHTMLtoPDF/src/test/ressources/";
}
}); CSSResolver cssResolver =
XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
Pipeline<?> pipeline =
new CssResolverPipeline(cssResolver,
new HtmlPipeline(htmlContext,
new PdfWriterPipeline(document, writer)));
XMLWorker worker = new XMLWorker(pipeline, true);
XMLParser p = new XMLParser(worker);
p.parse(new FileInputStream("src/test/ressources/other.html"));
document.close();
System.out.println("Done.");
}}
Try getting the image into a memory or byte stream object and then cast that image object to an itextsharp image one.
explore the overloads of iTextSharp.text.Image
EDIT:
Although the code is in C#, it might help you.
Get image from your local drive as:
Bitmap image1;
image1 = new Bitmap(#"C:\Documents and Settings\All Users\"
+ #"Documents\My Music\music.jpeg", true);
Note:: If you have the image on your application folder then we have functions to get the local file path of them in C#. Don't know about Java. Images from external site can be downloaded as
System.Net.WebClient client = new WebClient();
client.DownloadFile(imageURL, localPathname); // look into java to get local path
Now convert this byte stream to an image object as
MemoryStream imgMemoryStream = new MemoryStream(imgByteArray);
Image myImage = Drawing.Image.FromStream(imgMemoryStream);
Now acreate an iTextSharp image object from it and add it to your doucment as
iTextSharp.text.Image pic = iTextSharp.text.Image.GetInstance(myImage, System.Drawing.Imaging.ImageFormat.Jpeg);
document.Add(pic);
Hope this helps you.
I also faced to same issue..
but it was working with the image absolute path. it seems not working with remote path.
What id did here is save the image in temp location of file system and generates pdf , finally delete the image file from temp location.
<img src="/home/jboss/temp/imgs/img.png"/>
I was looking for same requirement and this is what worked for me:
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() {
return null;
}
#Override
public Image retrieve(String src) {
try {
Image img = com.itextpdf.text.Image.getInstance(new URL(src));
return Image.getInstance(img);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});

Categories

Resources