i have a requirement where i get byte array (byte[]) data from database, i need to save this data in a file and allow the user to save where ever he want to save, same as downloading the attachments.The file name and extension also i'm retrieving from database. I'm using java,spring-mvc for this.
Below is the code:
spring controller:
#RequestMapping(value="/getFile", method = RequestMethod.GET)
public ModelAndView getFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//logic to get the data from database
byte[] documentData = document.getDOCUMENTData();
String documentName = document.getDOCUMENTTITLE();
String documentExt = document.getDocumentExtension();
}
Please suggest, i know that using java.io.*, i can write the byte[] data in file and give file name and extension by taking the values declared above, but how can i allow users when clicked on "download file" icon to write the data and save that file where ever he wants same as downloading the attachment.Please suggest. Once user clicks on download file icon control comes to above controller.Thanks.
--EDIT--
Modified code:
#RequestMapping(value="/getFile", method = RequestMethod.GET)
public ModelAndView getFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//logic to get the data from database
byte[] documentData = document.getDOCUMENTData();
String documentName = document.getDOCUMENTTITLE();
String documentExt = document.getDocumentExtension();
response.setHeader("Content-Disposition", "attachment;filename="+userDoc.getDOCUMENT_TITLE());
long l = userDoc.getDOCUMENT_SIZE();
int size = (int)l;
response.setContentLength(size);
response.getWriter().write("hello");//i need to write byte[] but for test i kept string.
}
I want user to see save window so that he can save where ever he want same as downloading the attachments from mail.Thanks.
This is a code I'm usign for the same request
HTML page:
<h:commandButton value="Click Here to Download" action="#{reportBean.download}" />
BEAN:
public void download(){
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.setHeader("Content-Disposition", "attachment;filename="+file.getName());
response.setContentLength((int) file.length());
ServletOutputStream out = null;
try {
FileInputStream input = new FileInputStream(file);
byte[] buffer = new byte[1024];
out = response.getOutputStream();
int i = 0;
while ((i = input.read(buffer)) != -1) {
out.write(buffer);
out.flush();
}
FacesContext.getCurrentInstance().getResponseComplete();
input.close();
} catch (IOException err) {
err.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException err) {
err.printStackTrace();
}
}
}
Just make sure you have a File object named file
You have two options to achieve this:
One is to write the file in your server's local filesystem in an internet accesible folder. You can configure which of your server's local folders are accesible from internet in your Apache/IIS serttings. Then you update your HTML so your "download file" link points to that file through an URL.
The other option is, like #an3sarmiento did, to return the file as a byte[] stream to the browser. For this option to work, you have to send, along with the file content, a response header in which you tell the browser you are returning a downloadable file as a stream. You do that with the line:
response.setHeader("Content-Disposition", "attachment;filename="+[your file name]);
response.setContentLength([your file's length or bytes count]);
response.getWriter.write([your file's content as byte array]);
In the line above I assume you are working with Java Servlets and you have an HttpServletResponse variable named reponse, which you will respond to the browser's HTTP POST or GET request.
Related
I have a generic.exe file which doesn't contain any users detail in it.
I also have a REST API which takes the userId and returns a File to the client.
Now, what we want to implement in our project is that when someone hits the REST API, we want to take that generic.exe and rename it to manager_userId.exe and return back this "manager_userId.exe".
Points to be noted over here is that:
The generic.exe file should not be modified/deleted at all
When 2 users (userA and userB) hit that same API simultaneously , they should get their own copy of manager_userA.exe and manager_userB.exe
The code what I have written is
#RequestMapping(value = "/downloadExecutable", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = {MediaType.APPLICATION_OCTET_STREAM})
#ResponseBody
public Response downloadExecutable(#RequestBody DownloadExecutableRequest downloadExecutableRequest,
HttpServletRequest request, HttpServletResponse response) {
File file = downloadExecutable(downloadExecutableRequest, request, response,
getUserID(request), osDetails);
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment;filename=" + file.getName()).build();
}
public File downloadExecutable(DownloadExecutableRequest downloadExecutableRequest, HttpServletRequest request,
HttpServletResponse response, String userId, String osDetails) {
File file = null;
String path = "/home/genericCopy/generic.exe";
synchronized (this) {
BufferedWriter fileWriter = null;
try {
File source = null;
source = new File(path);
Path destination = Paths.get("/tmp/");
Files.copy(source, destination.toFile());
fileWriter = new BufferedWriter(new FileWriter(destination.getFileName().toString()+"_"+userId));
file = new File(destination.getFileName().toString());
} catch (IOException e) {
} finally {
if (fileWriter != null) {
fileWriter.close();
}
}
}
return file;
}
The code is working , but it is creating a temporary file and then renaming it and then returning it back but it will keep on creating the copies of the file for each request.
Is there any smarter way that i can achieve not to create such temporary copies of the user specific files and also handle a scenario when 2 users hit the API simultaneously ?
The name of the file which is downloaded by user has no relationship to the name of the file on disk.
You can just specify any name of the file in the header and the user will see the name.
Specifically, you would just set the filename you want the user to see to the Content-Disposition header and always load the same exe file from the disk.
Something like this:
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment;filename=executable_" + getUserID(request) + ".exe";
You don't need to do any copying in the downloadExecutable function.
You don't need to create a copy of generic.exe file to return it with changed name. You can use correctly parametrised Content-Disposition header, so it would return same file every time, with file name provided by user.
Here you can find example:
#RestController
public class DemoController {
#GetMapping(value = "/file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
#ResponseBody
public ResponseEntity downloadExecutable(#RequestParam("userId") String userId) throws IOException {
byte[] file = Files.readAllBytes(Paths.get("/home/genericCopy/generic.exe"));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=generic_" + userId + ".exe")
.contentLength(file.length)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(file);
}
}
and result of executing this method:
I'm working on a GWT application which gives every team in the company an overview about what they have to do.
The program is working, but now we want that the Excel table which you can download will be a .xlsx and not a .xls.
This whole project is new for me and I consider myself as a beginner in GWT.
In the code, when the filename is given for the Excel table, there is a +".xls" at the end. When I change it to +".xlsx" and test the application, the download still works. However, when I try to open the file in Excel, it shows me an error message and tells me the file is corrupted. (.xls works)
Can you explain to me how a download works in GWT with a serverSite generated Excel?
Maybe you have some ideas what causes the file to be corrupted
(sadly the programmer of this application is on holiday, so I cannot ask him)
public class Download extends HttpServlet {
private static final long serialVersionUID = 5580666921970339383L;
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String filename = (String)request.getSession().getAttribute(CrossReportConstants.ATTR_FILENAME);
byte[] data = (byte[])request.getSession().getAttribute(CrossReportConstants.ATTR_REPORT);
request.getSession().setAttribute(CrossReportConstants.ATTR_FILENAME, null);
request.getSession().setAttribute(CrossReportConstants.ATTR_REPORT, null);
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setContentLength(data.length);
try {
InputStream in = new ByteArrayInputStream(data);
ServletOutputStream out = response.getOutputStream();
byte[] outputByte = new byte[4096];
// 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) {
e.printStackTrace();
}
}
}
Now as you provided code you question can be easily answered:
The shown code defines a HttpServlet. Somewhere in your project there is a file called web.xml. In this file the class you showed is mapped to an url pattern, therefore you server knows that a specific url should be handled by this servlet.
The servlet you showed first extracts the file name and the file content out of the session. Additional the http response is prepared and the file content is written out. Now you just have to replace the content type of the response with the one for xlsx.
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
The browser which handles the http response now recognizes the download as a .xlsx file. The file extension does not really matter in this step, as you noticed.
When the original programmer of the servlet comes back from his hollidays, you should/could recommend him to use response.sendError() (with an appropriate http status code) instead of e.printStackTrace(). Then the user of the servlet can better understand if something do not work and who is to blame.
I have an image saved as a blob in a database. I send this image with a Spring MVC controller to the browser. That part works well with the following code:
#RequestMapping(value = "/img/{id}", method = RequestMethod.GET)
public void getImage(#PathVariable("id") Long id, HttpServletResponse response) {
Image image = imageRepository.findOne(id);
if (image != null) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>(image.getData(), headers, HttpStatus.CREATED);
}
return null;
}
But when i try to copy the image and paste it in, for example, Word, there is just a blank square. I tried to paste the image in Paint.NET and there it works again.
I tried some other methods of sending the image to the browser, for example:
#RequestMapping(value = "/img/{id}", method = RequestMethod.GET)
public void getImage(#PathVariable("id") Long id, HttpServletResponse response) {
Image image = imageRepository.findOne(id);
if (image != null) {
ByteArrayInputStream bis = new ByteArrayInputStream(image.getData());
response.reset();
response.setContentLength(image.getData().length);
response.setContentType("image/png");
response.setStatus(HttpServletResponse.SC_OK);
try {
OutputStream outputStream = response.getOutputStream();
IOUtils.copy(bis, outputStream);
bis.close();
outputStream.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This works also well with browser but copy and paste in applications like word does also not work. I'm clueless what i can try or where the mistake could be.
Saving the Image and inserting it in the application works but is unfortunately not an option.
Does anyone know what else i can try or what could go wrong?
Thanks in advance!
Ok i solved it. The problem in this case was actually the SSL-Connection forced by the Server. I set up a SecurityConstraint for the URL-Path for the images that excludes it from using SSL and now it works.
Edit: I'm still confused why copy and paste worked in Paint.NET but not in Word...
I am using OpenCsv API and now i am stuck in some problem.Here's my code
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
List<UserRegData> userRegDataList = new ArrayList<UserRegData>();
HttpSession session = request.getSession();
userRegDataList = (List<UserRegData>) session.getAttribute("referralData");
List<String[]> dataToWrite = new ArrayList<String[]>();
String csv = "E:\\carewave_backup\\csv\\UserReferral.csv";
CSVWriter writer = new CSVWriter(new FileWriter(csv));
for (UserRegData obj : userRegDataList) {
dataToWrite.add(new String[]{obj.getReferred_by_name(), obj.getInvitee_name(), obj.getInvitee_email(), obj.getInvitee_date(), obj.getIsInviteeRegistered(), obj.getDate_of_invitee_registered()});
}
writer.writeAll(dataToWrite);
writer.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
out.close();
}
}
This servlet basically retrieves list from session and writes it to csv file.This servlet is triggered after user clicks download csv button.Now what i need is, browser should give a download dialogue.Is there anyway to download it in csv format without writing it to file first?.
I assume you're asking about how to stream the output on the server directly to the client without writing it first to a temp file on the server.
You don't need to write the data to a file first.
Set the resonse content-type to text/csv
Call getOutputStream() on the response object
Write the contents of dataToWrite as individual lines to the output stream
No disk file needed.
I'm writing a Servlet in Java, that basically, gets a request with a XML in the Requests body, and then changes a few things in the XML and redirect/foreword the request with The new XML to a different Servlet that's on the same server, but its on a different web app.
How do redirect/foreword the request with The new XML? can i find code example any where?
this is what i have so far:
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String body = getBody(request);
MapXml mapXml = new MapXml(body,
"C:\\Projects\\XmlMapper\\output.xml","C:\\Projects\\XmlMapper\\output\\");
String outputXml = mapXml.getOutputXml();
}
public static String getBody(HttpServletRequest request) throws IOException {
String body = null;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
return body;
}
And i have no idea how to continue on from here. I'm new to the servlet world.. Thanks!!! Cheers:)
If both web-apps are on the same server, i.e. Tomcat
in its META-INF/context.xml set <Context crossContext="true" />
getServletContext().getContext("/app").getRequestDispatcher("f.jsp").forward(..);,
where app is the name of the other application.
Or what you maybe should do is, Use URLConnection to send request to any URL.
URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
About how to set XML in request, you can carry relatively larger amounts of data in POST request. You can also find the max limit of POST data.
just read the bytes that make up the XML file (using FileInputStream)
(if you dont have xml in file, use String to create ur xml)and send
them in the POST body. Make sure to set the content encoding
accordingly.
I am editing this for the 4th time, to add more details.
You can use Apache HTTP Client to post XML easily if its difficult for you to use Java's HTTP client.
String xml = "your xml";
PostMethod post = new PostMethod(strURL);
try {
StringRequestEntity requestEntity = new StringRequestEntity(xml);
post.setRequestEntity(requestEntity); ..
....
...
Because the xml will not be a small body for request,so you have to let the client post the new xml for you. or you can do:
share the same database or cache with remote web service, and forward the key of the data in database or cache.
use HttpClient to post the request for your client, with modified xml, and return the response from remote service to your client.
if you can make sure the xml body is small, you can just using GET method, forward the request to remote server
Let's rule out some possibilities first:
You cannot do response.sendRedirect("/otherapp/servlet.do") since it doesn't let you send POST data to another webapp.
You cannot use session since you're sending data across to a different webapp.
You cannot obviously pass full XML in a query string using GET.
Once those possibilities are ruled out only possible way I can think of is this:
Return to the calling page with modified XML and URL of other webapps's servelt in response
Let calling page immediately POST the modified XML to other webapps's servelt using simple Javascript