How can I reuse JAX-RS Response into HttpServletResponse? - java

I have a Servlet which makes a request to my Rest API, and I want it to return the API Response content to the final user through the HttpServletResponse.
The content is actually a .xls file to download which I put in the Response with the StreamingOutput Object.
How can I do that ? I can't cast the Response into a HttpServletResponse
Rest API method :
#GET
#Produces( MediaType.APPLICATION_JSON )
#Path("bla")
public Response getTopicByName() {
final Workbook wb = new HSSFWorkbook();
StreamingOutput stream = new StreamingOutput() {
#Override
public void write(OutputStream output) throws IOException, WebApplicationException {
wb.write(output);
}
};
responseBuilder = responseBuilder.entity(stream);
responseBuilder = responseBuilder.status(Response.Status.OK);
responseBuilder = responseBuilder.header("Content-Disposition", "attachment; filename=" + device + ".xls");
return responseBuilder.build();
}
Servlet POST method :
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(url);
Response res = target. request().get();
if (res.getStatus() == 200) {
// how to put res stream into response stream ?
ServletOutputStream stream = response.getOutputStream();
}
client.close();
}
EDIT :
I tried TedTrippin method and after finding out the way to recover an InputStream from the Response, it worked well.
But I keep getting corrupted xls files. And it is quite annoying. I don't get those corrupted files when I make the request directly from the browser.
Got any clues where it comes from ?
POST method :
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(url + param + format);
Response res = target.request().get();
if (res.getStatus() == 200) {
response.setHeader("Content-Disposition", "attachment; filename=test.xls");
InputStream in = res.readEntity(InputStream.class);
ServletOutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
while (in.read(buffer) >= 0) {
out.write(buffer);
}
out.flush();
}
client.close();
}

Simplest way is to read the response stream and write it straight to the response output stream. Either use a library function from IOUtils or Guava or pure java...
try (InputStream in = ...;
OutputStream out = ...) {
byte[] buffer = new byte[1024];
while (in.read(buffer) >= 0)
out.write(buffer);
} catch (IOException ex) {
...
}
A nicer (depending on your view) way would be to read/save the response as a temporary file then you could return that or write it to the output stream.
Third approach would be to create a pipe, but I don't think that would be applicable here.

Related

forwarding response to another action in struts and sending file in response

I'm forwarding an action to from doFilter method conditionally as the following code to another method :
public void dofilter(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request,
HttpServletResponse resp) {
String reportType = request.getParameter("reportType");
ActionForward actionForward = null;
try {
if (reportType.equals("completedChart")) {
actionForward = cmsGetCompeltedTasks(mapping, actionForm,request, resp);
} catch (Exception ex) {
ex.printStackTrace();
}
}
and my method that accepts the action and the response is that generates a jasper report file and sends it in the response :
public ActionForward cmsGetCompeltedTasks(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
JasperReport jasperReport = fileName = COMPLETED_TASK + format.format(new Date()).toString() + ".xlsx";
String filePath = servlet.getServletContext().getRealPath("") + fileName;
System.out.println(filePath);
JRXlsxExporter exporter = new JRXlsxExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, filePath);
exporter.exportReport();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
file = new File(filePath);
FileInputStream fileInputStream = new FileInputStream(filePath);
OutputStream responseOutputStream = response.getOutputStream();
int bytes;
while ((bytes = fileInputStream.read()) != -1) {
responseOutputStream.write(bytes);
}
responseOutputStream.flush();
fileInputStream.close();
responseOutputStream.close();
return mapping.findForward("cmsGetCompeltedTasks");
} catch (Exception e) {
e.printStackTrace();
} finally {
file.delete();
}
return null;
}
But no file is downloading and I get an exception:
java.lang.IllegalStateException: Cannot forward after response has been committed
You are writing to response in servlet and you should move it to JSP
just don't write to the response in the servlet. That's the responsibility of the JSP.
Move the lines using response to the JSP you redirect to
response.setContentType("application/vnd.openxmlformats- officedocument.spreadsheetml.sheet");
...
The problem was that I was firing Ajax request and I send the file to download in servlet response but the file to be download was handled by Ajax request in JavaScript on the success callback not the servlet response I handled the issue to send a direct URL to the file I want to download in the Ajax success call back and fire a new request to the that file specific URL.

Return HSSFWorkbook to client through HttpServletResponse

My Excel file seems to be generated but the function doesn't return anything:
#RequestMapping(value = "/excel", method = RequestMethod.POST, consumes = APPLICATION_JSON, produces = "application/vnd.ms-excel")
public void generateExcelExport(#RequestBody String rawContentParameters, final HttpServletRequest request, final HttpServletResponse response) throws FunctionalError, TechnicalError, IOException {
for (JsonNode personNode : rootNode) {
if (personNode instanceof ObjectNode) {
ObjectNode object = (ObjectNode) personNode;
object.remove("reportKey");
}
}
rawContentParameters = rootNode.toString();
ReportParameter reportParameters = new ReportParameter(reportCode);
HSSFWorkbook workbook = null;
try {
workbook = exportExcelService.getFile(reportParameters, rawContentParameters);
} catch (TechnicalError e1) {
redirectToErrorPage(request, response, rawContentParameters, Constants.ERR_BAD_REQUEST);
}
try {
if (workbook != null) {
workbook.write(response.getOutputStream());
}
response.flushBuffer();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=stuff");
}
}
What's wrong with it? Even though the return parameter is void, I read that the response should make the download possible.
You are just setting response headers and not sending the response.
Here is a link which sends a any file as response.
http://balusc.blogspot.de/2007/07/fileservlet.html
UPDATE:
Here is how you can write to response directly from HSSWorkbook. So replace the last part with the following.
HSSFWorkbook wb = getWorkbook(); // I think you already have a workbook
OutputStream out = response.getOutputStream();
try {
wb.write(out);
}
catch (IOException ioe) {
// handle exception
}
method = RequestMethod should be GET.

Add HTTP header to response in java socket server

I'm not sure where or what command to use to add the HTTP header to the response from the server.
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;
public class Response {
private static final int BUFFER_SIZE = 9999;
Request request;
BufferedOutputStream output;
//constructor para el output
public Response(BufferedOutputStream output){
this.output = output;
}
//Set del request
public void setRequest(Request request){
this.request = request;
}
public void sendResource() throws IOException{
File file = new File(Java_Server.Web_dir,request.getUri());
byte [] bytearray = new byte[(int) file.length()];
FileInputStream file_out = null;
if(file.exists())
file_out = new FileInputStream(file);
else{
String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 23\r\n" +
"\r\n" +
"<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());
}
BufferedInputStream bis = new BufferedInputStream(file_out);
try{
bis.read(bytearray,0,bytearray.length);
output.write(bytearray,0 , bytearray.length);
output.flush();
output.close();
return;
}catch (IOException e){
e.printStackTrace();
}
}
The contents is deliver to the browser but without the HTTP header and if a image is send for example, the browser doesn't show the image, it shows byte for byte.
The preferred way to do is, is to implement a Servlet and run it in a Servlet Container. Then you call the method setHeader on the HttpServletResponse object:
public class ExampleServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setHeader("X-Whatever-Header-Name-You-Want", "Value");
}
}

Return File From Resteasy Server

Hi, I wanted to return a file from a resteasy server. For this purpose, I have a link at the client side which is calling a rest service with ajax. I want to return the file in the rest service. I tried these two blocks of code, but both didn't work as I wanted them to.
#POST
#Path("/exportContacts")
public Response exportContacts(#Context HttpServletRequest request, #QueryParam("alt") String alt) throws IOException {
String sb = "Sedat BaSAR";
byte[] outputByte = sb.getBytes();
return Response
.ok(outputByte, MediaType.APPLICATION_OCTET_STREAM)
.header("content-disposition","attachment; filename = temp.csv")
.build();
}
.
#POST
#Path("/exportContacts")
public Response exportContacts(#Context HttpServletRequest request, #Context HttpServletResponse response, #QueryParam("alt") String alt) throws IOException {
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=temp.csv");
ServletOutputStream out = response.getOutputStream();
try {
StringBuilder sb = new StringBuilder("Sedat BaSAR");
InputStream in =
new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
byte[] outputByte = sb.getBytes();
//copy binary contect to output stream
while (in.read(outputByte, 0, 4096) != -1) {
out.write(outputByte, 0, 4096);
}
in.close();
out.flush();
out.close();
} catch (Exception e) {
}
return null;
}
When I checked from the firebug console, both of these blocks of code wrote "Sedat BaSAR" in response to the ajax call. However, I want to return "Sedat BaSAR" as a file. How can I do that?
Thanks in advance.
There're two ways to to it.
1st - return a StreamingOutput instace.
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response download() {
InputStream is = getYourInputStream();
StreamingOutput stream = new StreamingOutput() {
public void write(OutputStream output) throws IOException, WebApplicationException {
try {
output.write(IOUtils.toByteArray(is));
}
catch (Exception e) {
throw new WebApplicationException(e);
}
}
};
return Response.ok(stream, MediaType.APPLICATION_OCTET_STREAM).header("content-disposition", "attachment; filename=\"temp.csv\"").build();
}
You can return the filesize adding Content-Length header, as the following example:
return Response.ok(stream, MediaType.APPLICATION_OCTET_STREAM).header("content-disposition", "attachment; filename=\"temp.csv\"").header("Content-Length", getFileSize()).build();
But if you don't want to return a StreamingOutput instance, there's other option.
2nd - Define the inputstream as an entity response.
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response download() {
InputStream is = getYourInputStream();
return Response.code(200).entity(is).build();
}

I can´t open a .pdf in my browser by Java

I´m trying to open a pdf that I have created using iText library in my browser, but it fails.
This is the code I´m using to send to browser
File file = new File(path);
try{
//InputStream stream=blob.getBinaryStream();
InputStream streamEntrada = new FileInputStream(file);
//ServletOutputStream fileOutputStream = response.getOutputStream();
PrintWriter print = response.getWriter();
int ibit = 256;
while ((ibit) >= 0)
{
ibit = streamEntrada.read();
print.write(ibit);
}
response.setContentType("application/text");
response.setHeader("Content-Disposition", "attachment;filename="+name);
response.setHeader("Pragma", "cache");
response.setHeader("Cache-control", "private, max-age=0");
streamEntrada.close();
print.close();
return null;
}
catch(Exception e){
return null;
}
}
I tried with FileOutputStream but isn´t works. I´m desperate.
Thank you.
Now, I´m trying this way, but it doesn´t work:
public class MovilInfoAction extends DownloadAction{
protected StreamInfo getStreamInfo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
//Here the creation of the PDF
//Storing data
PdfData dPdf = pdf.drawPDF(terminal);
String path = dPdf.getPath();//Path
String name = dPdf.getName()+".pdf";//Pdf´s name
String contentType = "application/pdf";//ContentType
response.setContentType(contentType);
response.setHeader("Content-Disposition","attachment; filename="+name);
response.setHeader("Cache-control", "private, max-age=0");
response.setHeader("Content-Disposition", "inline");
File file = new File(path);
byte[] pdfBytes = es.vodafone.framework.utils.Utils.getBytesFromFile(file);
return new ByteArrayStreamInfo(contentType, pdfBytes);
}
protected class ByteArrayStreamInfo implements StreamInfo {
protected String contentType;
protected byte[] bytes;
public ByteArrayStreamInfo(String contentType, byte[] bytes) {
this.contentType = contentType;
this.bytes = bytes;
}
public String getContentType() {
return contentType;
}
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(bytes);
}
}
}
You specify the mimetype as application/text, when it should be application/pdf.
You should set the Header and ContentType before you write the data.
And set the Content Type to application/pdf.
change
response.setContentType("application/text");
to
response.setContentType("application/pdf");
and if you want your pdf to open in browser then make following change
response.setHeader("Content-Disposition", "inline");
Put the filename in double quote "
response.setHeader("Content-Disposition","attachment; filename=\"" + attachmentName + "\"");
Android Default Browser requires GET Request. It does not understand POST Request and hence cannot download the attachment. You can send a GET request as by sending GET request, it resolved my problem. Android browser generates a GET request on its own and sends it back to server. The response received after second request will be considered final by the browser even if GET request is sent on first time by the servlet.

Categories

Resources