Can't download file. Browser opens it instead. - spring-mvc

I have tried a lot of contentTypes and headers I have seen here but still can't figure out what I am doing wrong. I have the following Spring Controller:
#RequestMapping(value = "/anexo/{id}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<String> getAnexoById(#PathVariable int id, HttpServletResponse response) {
Anexo a = anexoDAO.getAnexo(id);
if (a == null)
return new ResponseEntity<String>(HttpStatusMessage.NOT_FOUND, HttpStatus.NOT_FOUND);
else {
try {
File dir = new File("temp");
if (!dir.exists())
dir.mkdirs();
String filePath = dir.getAbsolutePath() + File.separator + a.getName();
File serverFile = new File(filePath);
FileInputStream fistream = new FileInputStream(serverFile);
org.apache.commons.io.IOUtils.copy(fistream, response.getOutputStream());
response.setHeader("Content-Disposition", "attachment; filename=" + a.getName());
response.setContentType("application/octet-stream");
response.setHeader("Content-Length", String.valueOf(serverFile.length()));
response.setHeader("Content-Transfer-Encoding", "binary");
response.flushBuffer();
System.out.println(response.toString());
return new ResponseEntity<String>(HttpStatus.OK);
} catch (IOException ex) {
return new ResponseEntity<String>("Exception on getting file", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
I also have tried with and without #ResponseBody.
The user will be able to upload any type of file to the server and then he will be able to download through this controller. The problem is that instead of the download window, the browser open the file in the page. How can I make it download?
Thanks in advance

This work for me:
#ResponseBody
void getOne(#PathVariable("id") long id, HttpServletResponse response) throws IOException {
MyFile file = fileRepository.findOne(id);
if(file == null) throw new ResourceNotFoundException();
response.setContentType(file.getContentType());
response.setHeader("Content-Disposition", "attachment; filename=\""+ file.getName() +"\"");
response.setContentLength(file.getData().length);
FileCopyUtils.copy(file.getData(), response.getOutputStream());
}
Where MyFile is a class like this:
class MyFile {
private Long id;
private String contentType;
private String name;
private bit[] data;
...
}

Related

Blank CSV file generated,need to write data stored inside List<List<Object>

I need to create and download the CSV file, and for this I am using OpenCSV with Spring MVC, the data need to be written is holding by my class name CsvDataDto.
public class CsvDataDto {
private String fileName;
List<String> header=new ArrayList<>();;
private String heading;
List<List<Object>> data=new ArrayList<>();
//getters and setters
}
The main data contains file header (eg: userid,fname,lastname,rollno) and actual data (eg. 1,101,john,doe,1001).
File header is hold by List<String> header
and The file data is hold by List<List<Object>> data
and here is the controller method which set all the required data
#RequestMapping(value = "/export_data")
public void downloadDataInCsv(
#RequestParam("type") String type,
#RequestParam("tID") String tableId,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
if (type.equals("csv")) {
CsvDataDto dataDTO = new CsvDataDto();
dataDTO.setFileName("Table_Data");
dataDTO.getHeader().add("User Id");
dataDTO.getHeader().add("First Name");
dataDTO.getHeader().add("Last Name");
dataDTO.getHeader().add("Roll No");
dataDTO.getHeader().add("Email ID");
dataDTO.getHeader().add("Gender");
List<UserInfo> list = userInfoDao.findById(tableId);
for (UserInfo infoList : list) {
List<Object> newList = new ArrayList<>();
newList.add(infoList.getUserId());
newList.add(infoList.getFirstName());
newList.add(infoList.getLastName());
newList.add(infoList.getRollNo());
newList.add(infoList.getEmail());
newList.add(infoList.getGender());
dataDTO.getData().add(newList);
}
ExportCsvUtil.downloadCsv(request, response, dataDTO);
}
Now the downloadCsv() implementation
public static void downloadCsv(HttpServletRequest request, HttpServletResponse response, CsvDataDto csvDataDto) throws IOException {
List<String[]> records = new ArrayList<>();
String csvFileName = csvDataDto.getFileName();
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=" + csvDataDto.getFileName() + ".csv");
response.setContentType("text/csv");
response.setHeader(headerKey, headerValue);
CSVWriter writer = new CSVWriter(new FileWriter(csvFileName));
String[] headerArr = new String[csvDataDto.getHeader().size()];
headerArr = csvDataDto.getHeader().toArray(headerArr);
records.add(headerArr);
for (List<Object> objList : csvDataDto.getData()) {
System.out.println("object list:" + objList);
String[] fileData = new String[objList.size()];
fileData = objList.toArray(fileData);
records.add(fileData);
}
writer.writeAll(records);
writer.close();
System.out.println(writer);
}
}
I am stuck here,as I explore tons of examples where the instructors simple pass the data in writeNext() method.
writer.writeNext(csvDataDto);
But I know that it will not work as i expected.File is successfully downloaded but blank, no data is write over it.
I want to implement the logic in such a way, so I get the CSV like below
userid, fname,lastname,rollno,gender (List<String> header)
1 , john, doe ,1001, M (List<List<Object>> data)
2 , Rose, Mary ,1002, F
3 , Jack, Jill ,1003, M
What is the best way to achieve the same by using writeNext().
#RequestMapping(value = "/export_data")
public void downloadDataInCsv(
#RequestParam("type") String type,
#RequestParam("tID") String tableId,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
if (type.equals("csv")) {
List<UserInfo> list = userInfoDao.findById(tableId);
ExportCsvUtil.downloadCsv(request, response, list);
}
}
private void downloadCsv(HttpServletRequest request, HttpServletResponse response, List<UserInfo> list) throws IOException {
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=Table_Data.csv");
response.setContentType("text/csv");
response.setHeader(headerKey, headerValue);
try (final CSVWriter writer = new CSVWriter(response.getWriter(), ",")) {
writer.writeNext(new String[]{"User Id", "First Name", "Last Name", "Roll No", "Email ID", "Gender"});
for (UserInfo entry: list) {
// cast/convert to String where needed
writer.writeNext(new String[]{entry.getUserId()+"", entry.getFirstName(), entry.getLastName(),entry.getRollNo(),entry.getEmail(),entry.getGender()});
}
writer.close();
}
}

HttpServletResponse as an argument

I am pretty new to servlets and I would like to ask a kind of silly question.
I have a method that has an HttpServletResponse argument and I need to call this method from my main method to run the Java program.
The thing is I do not know what should I pass as value for this argument.
Let's say I have this class that comes from CrystalReports:
private static void exportIt(ReportClientDocument clientDoc, ExportOptions exportOptions, HttpServletResponse response, boolean attachment, String mimeType, String extension)
throws ReportSDKExceptionBase, IOException {
InputStream is = null;
try {
is = new BufferedInputStream(clientDoc.getPrintOutputController().export(exportOptions));
byte[] data = new byte[1024];
response.setContentType(mimeType);
if (attachment)
{
String name = clientDoc.getReportSource().getReportTitle();
if (name == null)
{
name = "CrystalReportViewer";
}
else
{
name = name.replaceAll("\"", "");
}
response.setHeader("Content-Disposition",
"attachment; filename=\"" + name + "."+extension+"\"");
}
OutputStream os = response.getOutputStream();
while (is.read(data) > -1) {
os.write(data);
}
} finally {
if (is != null) {
is.close();
}
}
}
When I try to call the exportIt method I need to pass something in the HTTPServletResponse but I do not know what is the exact value.
Thank you for your help,

Java Apache HttpClient error uploading files with InputStream

Am having the same issue with inputstream. Can you please share more details about your fix please.
Thanks,
Harsha
link to your question
Java Apache HttpClient error uploading files
There is another simple way we can override InputStreamBody.getContentLength without a need to create our own ContentBody implementation if you know your contentLength-
InputStreamBody inputStreamBody = new InputStreamBody(inputStream, ContentType.APPLICATION_OCTET_STREAM, fileName){
#Override
public long getContentLength(){return contentLength;}
};
MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addPart("dataAsStream", inputStreamBody)
.build();
The code of the extended org.apache.http.entity.mime.content.InputStreamBody will be something like this. You will need to somehow calculate the correct content length before creating the InputStreamBodyExtended
public class InputStreamBodyExtended extends InputStreamBody {
private long contentLength = -1;
public InputStreamBodyExtended(InputStream in, String filename, long contentLength) {
super(in, filename);
this.contentLength = contentLength;
}
public InputStreamBodyExtended(InputStream in, ContentType contentType, long contentLength) {
super(in, contentType);
this.contentLength = contentLength;
}
public InputStreamBodyExtended(InputStream in, ContentType contentType,
String filename, long contentLength) {
super(in, contentType, filename);
this.contentLength = contentLength;
}
#Override
public long getContentLength() {
return contentLength;
}
}
An other option is org.apache.http.entity.mime.content.ByteArrayBody, if don't know what is the size beforehand (!!! You have to be sure that the content of the inputStream will fit into the memory of JVM):
InputStream inputStream = // get your input stream somehow
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i;
byte buff[] = new byte[4096];
while( -1 != (i = inputStream.read(buff))){
baos.write(buff, 0, i);
}
ByteArrayBody bab = new ByteArrayBody(baos.toByteArray(), "fileName1");
Here is how I solved it.
public class CustomInputStreamBody extends InputStreamBody {
private InputStream inputStream;
private BufferedReader bufferedReader = null;
StringBuilder stringBuilder = null;
public CustomInputStreamBody(InputStream in,ContentType contentType){
super(in,contentType);
this.inputStream=in;
}
#Override
public long getContentLength() {
int length=0;
byte[] bytes=null;
try {
bytes = IOUtils.readBytesFromStream(inputStream);
// iterate to get the data and append in StringBuilder
System.out.println("___________"+bytes.length);
}catch (IOException ioe){
ioe.printStackTrace();
}
return bytes.length;
}

Upload file from applet to servlet using apache fileupload

To accomplish:
Upload a file from my local to server using an applet and servlet using apache fileupload jar.
Tried:
I have used a simple jsp, with a browse button and posted the action to my servlet (where I used apache fileupload). I was successful in uploading the file to the server.
Issue:
I am trying to upload a file, from my local machine, using an applet. I do not want to manually select files, instead upload files that are present in a specific folder. For now I have hardcoded the folder. I am able to look at the folder and get the list of files I want to upload.
Also, I have successfully established a connection from my applet to servlet.
Issue arises at the upload.parseRequest(request) in the servlet. I'm thinking its because the applet cannot post to servlet's request object.
Also, I have set the request type to multipart/form-data in my applet.
Right now, I am trying to pass the absolute path of the file to servlet and upload.
I have seen other posts where byte stream data is passed from applet to servlet, but the servlet uses the traditional File.write.
For me, it is mandatory to achieve this using apache fileupload.
Please suggest on how to pass a file/file path from applet to servlet, where the upload is handled by apache fileupload.
Below are my FileUploadHandler (where the HTTP requests are handled) and FileUpload(which is my applet)
Below is my FileUpload Handler:
#WebServlet(name = "FileUploadHandler", urlPatterns = { "/upload" })
#MultipartConfig
public class FileUploadHandler extends HttpServlet {
String uploadFolder ="";
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("doPost-servlet URL is: "
+ request.getRequestURL());
try {
uploadFolder = fileToUpload(request);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
uploadFolder = getServletContext().getRealPath("")+ File.separator;
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// process only if its multipart content
if (ServletFileUpload.isMultipartContent(request)) {
System.out.println("Yes, it is a multipart request...");
try {
List<FileItem> multiparts = upload.parseRequest(request);
System.out.println("Upload.parseRequest success !");
for (FileItem item : multiparts) {
if (!item.isFormField()) {
String name = new File(item.getName()).getName();
item.write(new File(uploadFolder + File.separator
+ name));
}
}
System.out.println("File uploaded to server !");
// File uploaded successfully
request.setAttribute("message", "File Uploaded Successfully");
} catch (Exception ex) {
request.setAttribute("message", "File Upload Failed due to "
+ ex);
}
} if(!ServletFileUpload.isMultipartContent(request)){
throw new ServletException("Content type is not multipart/form-data");
}
doGet(request, response);
//request.getRequestDispatcher("/result.jsp").forward(request, response);
OutputStream outputStream = response.getOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject("Success !");
objectOutputStream.flush();
objectOutputStream.close();
}
private String fileToUpload(HttpServletRequest request) throws IOException,
ClassNotFoundException {
ServletInputStream servletIn = request.getInputStream();
ObjectInputStream in = new ObjectInputStream(servletIn);
String uploadFile = (String) in.readObject();
System.out.println("Value in uploadFolder is: " + uploadFile);
return uploadFile;
}
Below is the fileupload applet:
public class FileUpload extends Applet {
private JButton capture;
private JTextField textField;
private final String pathDirectory = "C:\\";
private final String captureConfirmMessage = "Are you sure you want to continue?";
private final String confirmDialogTitle = "Confirm upload";
final File folder = new File(pathDirectory);
public void init() {
upload= new JButton("Upload");
textField = new JTextField();
capture.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int selection = JOptionPane.showConfirmDialog(upload,
uploadConfirmMessage, confirmDialogTitle,
JOptionPane.YES_NO_OPTION);
if (selection == JOptionPane.OK_OPTION) {
listFilesForFolder(folder);
} else if (selection == JOptionPane.CANCEL_OPTION) {
JOptionPane.showMessageDialog(upload,
"You have aborted upload", "Upload Cancelled", 2);
}
}
});
add(upload);
add(textField);
}
public void listFilesForFolder(final File folder) {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
try {
onSendData(fileEntry.getAbsolutePath());
System.out.println(fileEntry.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private URLConnection getServletConnection() throws MalformedURLException,
IOException {
// Open the servlet connection
URL urlServlet = new URL("http://localhost:8081/UploadFile/upload");
HttpURLConnection servletConnection = (HttpURLConnection) urlServlet
.openConnection();
// Config
servletConnection.setDoInput(true);
servletConnection.setDoOutput(true);
servletConnection.setUseCaches(false);
servletConnection.setDefaultUseCaches(false);
servletConnection.setRequestProperty("Content-Type", "multipart/form-data;");
servletConnection.connect();
return servletConnection;
}
private void onSendData(String fileEntry) {
try {
// Send data to the servlet
HttpURLConnection servletConnection = (HttpURLConnection) getServletConnection();
OutputStream outstream = servletConnection.getOutputStream();
ObjectOutputStream objectOutputStream= new ObjectOutputStream(
outstream);
objectOutputStream.writeObject(fileEntry);
// Receive result from servlet
InputStream inputStream = servletconnection.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(
inputStream);
String result = (String) objectInputStream.readObject();
objectInputStream.close();
inputStream.close();
out.flush();
out.close();
// Display result on the applet
textField.setText(result);
} catch (java.net.MalformedURLException mue) {
mue.printStackTrace();
textField.setText("Invalid serlvetUrl, error: " + mue.getMessage());
} catch (java.io.IOException ioe) {
ioe.printStackTrace();
textField.setText("Couldn't open a URLConnection, error: "
+ ioe.getMessage());
} catch (Exception e) {
e.printStackTrace();
textField.setText("Exception caught, error: " + e.getMessage());
}
}
public void paint(Graphics g) {
g.drawString("Click the button above to capture", 5, 50);
}
I could finally succeed posting the request to the servlet from the applet.
It was a simple logic that I was missing. I did not add the header and trailer while posting to the servlet, which was the key, in the servlet to identify the incoming request as a multipart data.
FileInputStream fileInputStream = new FileInputStream(new File(
fileEntry));
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream
.writeBytes("Content-Disposition: form-data; name=\"upload\";"
+ " filename=\"" + fileEntry + "\"" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
// create a buffer of maximum size
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// read file and write it into form
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
System.out.println(fileEntry + " uploaded.");
}
// send multipart form data necesssary after file data
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(twoHyphens + boundary + twoHyphens
+ lineEnd);
I added the header and trailer and also used this to create the URL connection.
private URLConnection getServletConnection() throws MalformedURLException,
IOException {
// Open the servlet connection
URL urlServlet = new URL("http://localhost:8083/UploadFile/upload");
HttpURLConnection servletConnection = (HttpURLConnection) urlServlet
.openConnection();
// Config
servletConnection.setDoInput(true);
servletConnection.setDoOutput(true);
servletConnection.setUseCaches(false);
servletConnection.setDefaultUseCaches(false);
servletConnection.setRequestMethod("POST");
servletConnection.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + this.boundary);
servletConnection.setRequestProperty("Connection", "Keep-Alive");
servletConnection.connect();
return servletConnection;
}
Then, in the servlet, I was just reading the data using upload.ParseRequest(request).
Thank you for the help.

Write Glassfish output into servlet html page

How to redirect Glassfish server output into HttpServletResponse.out? I am making servlet in NetBeans.
here is a working example, just expose this as a servlet
public class ReadLogs extends HttpServlet {
private static final String CONTENT_TYPE = "text/html; charset=UTF-8";
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.append("<html>\n<head>\n\n");
out.append("<script>function toBottom()" + "{"
+ "window.scrollTo(0, document.body.scrollHeight);" + "}");
out.append("\n</script>");
out.append("\n</head>\n<body onload=\"toBottom();\">\n<pre>\n");
try {
File file = new File("C:\\pathToServerLogFile");
BufferedReader in = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
while (in.ready()) {
String x = in.readLine();
sb.append(x).append("<br/>");
}
in.close();
out.append("\n</pre>\n</body>\n</html>");
out.close();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
UPDATE
If you need to print only the last portion of the file use this after line "in.close();"
//print only 1MB Oof data
if(sb.length()>1000000){
out.append(sb.substring(sb.length()-1000000, sb.length()));
}else{
out.append(sb.toString());
}
So.. to print only lines which appeared after invoking script I've made such code:
BufferedReader reader = new BufferedReader(new FileReader("/path/to/server/log/server.log"));
int lines = 0;
while (reader.readLine() != null) {
lines++;
}
reader.close();
BufferedReader reader2 = new BufferedReader(new FileReader("/path/to/server/log/server.log"));
String strLine;
int i = 0;
while (i != lines) {
reader2.readLine();
i++;
}
while ((strLine = reader2.readLine()) != null) {
out.println(stringToHTMLString(strLine));
out.println("<br>");
}
reader2.close();
When servlet starts it counts lines in server log (saves it in variable i), then after clicking on action form it read lines which indexes are higher than i and displays it on html page. I've used function stringToHTMLString which I found somewhere on stackoverflow.
Greets.

Resources