Return HSSFWorkbook to client through HttpServletResponse - java

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.

Related

ResponseEntity<InputStreamResource> return two service methods

I have two services returning two different ResponseEntity.
public ResponseEntity<InputStreamResource> getA(...) {
return ResponseEntity
.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.contentLength(out.size())
.body(new InputStreamResource(bis)); }
public ResponseEntity<InputStreamResource> getB(...) {
return ResponseEntity
.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.contentLength(out.size())
.body(new InputStreamResource(bis)); }
Each service has a controller that calls and returns.
public ResponseEntity<InputStreamResource> getA(...) {
return aService.getA(...) }
public ResponseEntity<InputStreamResource> getB(...) {
return bService.getB(...) }
I'm trying to create another controller which does and return both services at once.
public ResponseEntity<InputStreamResource> getAB(...) {
return aService.getA(...) *and* bService.getB(...) ?????? }
not sure how to combine two ResponseEntities returns into one.
Returning ResponseEntity from a Service method is not a good idea.
It's the Controller layer which should be responsible for generating ResponseEntity Object. That is his business not of the Service Layer. Similarly, the responsibility of the Service Layer is to prepare some kind of a DTO object based on the given input and then the Controller will wrap around that DTO and send it as a response.
So, I suggest to do some structural change here.
Service Layer
public InputStreamResource getA(...) {
return A
}
public InputStreamResource getB(...) {
return B
}
Controller Layer
public ResponseEntity<InputStreamResource> getA(...) {
return new ResponseEntity<>(aService.getA(...) (
}
public ResponseEntity<InputStreamResource> getB(...) {
return new ResponseEntity<>(bService.getB(...) )
}
To merge 2 streams
If you are targeting to stream 2 different pdf documents one by one, then I think the option will be to merge pdf documents in memory first with whatever pdf library you might be using. Then create a single InputStreamResource as Response.
But, If the streams can be run in sequence, then below is a working example to merge 2 streams using SequenceInputStream -
#RequestMapping(
path = "/sayHello",
method = RequestMethod.GET,
produces = MediaType.TEXT_PLAIN_VALUE
)
public ResponseEntity<InputStreamResource> get() {
byte[] inputBytes1 = "Hello".getBytes();
// 1st stream has "Hello" text
ByteArrayInputStream baos1 = new ByteArrayInputStream(inputBytes1);
byte[] inputBytes2 = "World".getBytes();
// 2nd stream has "World" text
ByteArrayInputStream baos2 = new ByteArrayInputStream(inputBytes2);
// combined stream will have "HelloWorld" text
SequenceInputStream combinedStream = new SequenceInputStream(baos1, baos2);
InputStreamResource inputStreamResource = new InputStreamResource(combinedStream);
return ResponseEntity.ok().body(inputStreamResource);
}
Output ->
curl -X GET http://localhost:8083/sayHello
HelloWorld
You can try via this way:
public ResponseEntity<List<InputStreamResource> getAAndB(...) {
private List<InputStreamResource> result = new ArrayList<>();
result.add(aService.getA(...));
result.add(bService.getB(...));
return ResponseEntity.ok().body(result)); }
}
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
#RestController
public class ReportController {
private static final Logger LOGGER = ...
#Autowired
private ReportManager manager;
#GetMapping("/reportcard/students")
public ResponseEntity<InputStreamResource> getStudentReportCard(parameters...) throws ServiceException {
List<InputStream> studentReportList = manager.getStudentReports(parameters.... );
HttpHeaders headers = getHeaders(Constants.STUDENTS_REPORT_CARD);
Document document = new Document(PageSize.LETTER);
ByteArrayOutputStream outputStream = null;
try {
outputStream = new ByteArrayOutputStream();
PdfCopy copy = new PdfCopy(document, outputStream);
document.open();
for (InputStream file : studentReportList) {
copy.addDocument(new PdfReader(file)); // writes directly to the output stream
}
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen()) {
document.close();
}
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
InputStreamResource inputStreamResource = new InputStreamResource(new ByteArrayInputStream(outputStream.toByteArray()));
return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_PDF).body(inputStreamResource);
}
private HttpHeaders getHeaders(String fileName) {
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
headers.set("Content-disposition", "attachment; filename=" + fileName);
return headers;
}
public class ReportManagerImpl implements ReportManager {
private static final Logger LOGGER = ...
#Autowired
private HttpClient httpClient;
#Override
public List<InputStream> getStudentReports(parameters...)
throws ServiceException {
List<InputStream> studentReportList = new Vector<InputStream>();
List<String> learnersList = //list of students
String reportUrl = //url
for (String learner : learnersList) {
studentReportList.add(getHttpResponse(reportUrl + learner));
}
return studentReportList;
}
private InputStream getHttpResponse(String url) throws ServiceException {
try {
HttpResponse response = httpClient.execute(new HttpGet(url));
HttpEntity entity = response.getEntity();
return entity.getContent();
} catch (IOException e) {
throw new ServiceException(e.getMessage());
}
}

JSF command button can be clicked only once when calling servlet for file download

I have some command buttons in a jsf, one of which when clicked when create a file and download. In the action class that handle the jsf action , I create the url object that has the URL for calling the Servlet.
This all works , the file is downloaded one time when I click on the button , but the issue is , I cannot click on the button or any other command buttons on the page after this. Why is the request not complete? Please help.
<h:commandButton id="filedownloadbtn" action="#{fileDownloadInit.submit}" value = "thisform">
Action
try {
String baseURL = facesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
String url = baseURL + "/DataloadServlet";
facesContext.getCurrentInstance().getExternalContext().redirect(url);
return null;
} finally {
facesContext.responseComplete();
}'
DataloadServlet
public Object[] getFileNameAndData(HttpServletRequest request)
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
//does some processing...
return new Object[] {fileName, stream.toByteArray()};
}
FileDownloadservlet
public abstract class FileDownloadservlet extends javax.servlet.http.HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Object[] file = getFileNameAndData(request);
if (file != null)
{
String fileName = (String)file[0];
byte[] fileData = (byte[])file[1];
response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName +"\"");
response.setHeader("Cache-Control", "no-cache, no-store"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
String contentType = "application/vnd.ms-excel";
response.setContentType(");
response.setContentLength(fileData.length);
try
{
OutputStream output = response.getOutputStream();
output.write(fileData);
output.flush();
output.close();
}
catch (IOException ex)
{
}
}
}

Can't communicate MultiPart/data in Test (Jersey/Junit)

So i've had some trouble with doing Unit test of a method that parse PDFs
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public Response parsingPdfOrange(#FormDataParam("fichier") InputStream uploadedInputStream,
#FormDataParam("fichier") FormDataContentDisposition fileDetail) {
try {
String uploadedFileLocation = "D:/tmp/doc.pdf";
String info = "facture Orange:"
+ OrangeService.ParseFacture(uploadedFileLocation, uploadedInputStream).toString();
return Response.status(201).entity(info).build();
which works fine my url give my the good result etc but
#Override
protected Application configure() {
return new ResourceConfig(OrangeWebService.class).register(MultiPartFeature.class);
}
#Override
protected void configureClient(ClientConfig config) {
config.register(MultiPartFeature.class);
}
#Test
public void parsePDF_NullPointerExcpetion() throws Exception {
try {
FileDataBodyPart filePart = new FileDataBodyPart("file", new File(pathtoRessources));
FormDataMultiPart formDataMultipart = new FormDataMultiPart();
FormDataMultiPart multipart = (FormDataMultiPart) formDataMultipart.bodyPart(filePart);
Response response = (target("pdf").request().post(Entity.entity(multipart, multipart.getMediaType())));
System.out.println(response);
response.close();
} catch (Exception e) {
e.printStackTrace();
}
this is my test code and the pb is here: it seems my FormDataMultiPart is fine but when i do Entity.entity(multipart, multipart.getMediaType() it gives back a null value because i get a nullPointerException on it.
I need help, Thanks a lot.
The file part name is "fichier"
#FormDataParam("fichier") InputStream uploadedInputStream
But you are sending it as "file"
FileDataBodyPart filePart = new FileDataBodyPart("file", new File(pathtoRessources));
Fix that.

How can I reuse JAX-RS Response into HttpServletResponse?

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.

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

Categories

Resources