ameenulla
ameenulla

Reputation: 33

How to write a file download to response in JSP file

I'm getting a java.lang.IllegalStateException when I try to get a ServletOutputStream object from the response object. Below is my code:

<%@ page import="java.util.*,java.io.*"%>             

<%
try {
    System.out.print("request came");
    File f = new File ("E:/dd.txt");

    String name = f.getName().substring(f.getName().lastIndexOf("/") + 1,f.getName().length());
    InputStream in = new FileInputStream(f);

    ServletOutputStream outs = response.getOutputStream();

    response.setContentType ("application/txt");
    response.setHeader ("Content-Disposition", "attachment; filename="+f.getName()+"");
    int bit = 256;
    int i = 0;
    try {
        while ((bit) >= 0) {
            bit = in.read();
            outs.write(bit);
        }
    } catch (IOException ioe) {
        ioe.printStackTrace(System.out);
    }
    outs.flush();
    outs.close();
    in.close();         
} catch (Exception ioe) {
    ioe.printStackTrace(System.out);
}
%>

The following is the stacktrace:

java.lang.IllegalStateException
   at org.apache.jasper.runtime.ServletResponseWrapperInclude.getOutputStream(ServletResponseWrapperInclude.java:63)
   at org.apache.jsp.html.portlet.vitage.custom.QUADWAVE.Procfiledownloadess1_005f36901_005f48.filedownload.downloadscreen_jsp._jspService(downloadscreen_jsp.java:5
   at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
   at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:331)
   at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:329)
   at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

Upvotes: 3

Views: 17417

Answers (4)

Syed
Syed

Reputation: 11

I suggest writing the file download code in the servlet. Something like this:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

        ServletContext sc = request.getServletContext();
        String logFilename = (String) sc.getAttribute("scriptFilename");
        String logFilepath = DOWNLOAD_DIR + File.separator + logFilename + LOGFILE_EXTN;
               log.debug("file name received: "+logFilename);
               log.debug("log file path: "+logFilepath);

        File logFile = new File(logFilepath);
        OutputStream outStream = null;
        FileInputStream inputStream = null;

        if(logFile.exists() && logFile.length()!=0) {

            log.debug(logFile.getName()+": file exits in the directory.");
            String MIME_TYPE = "application/octet-stream";
            response.setContentType(MIME_TYPE);

            String headerKey = "Content-Disposition";
            String headerValue = String.format("attachment; filename=\"%s\"", logFile.getName());
            response.setHeader(headerKey, headerValue);

            try {

                outStream = response.getOutputStream();
                inputStream = new FileInputStream(logFile);
                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead = -1;

                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outStream.write(buffer, 0, bytesRead);
                }

            }catch(IOException io) {

                log.debug("exception occured.."+io.getMessage());

            } finally {

                if(inputStream != null) {

                    inputStream.close();
                }

                outStream.flush();
                if(outStream != null) {

                    outStream.close();
                }
            }

        }else {

            log.debug(logFile.getName()+" :file not found in the directory.");
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Jmeter Log file not found");
        }
    }

And you can have a button in your jsp say 'download' where onclick, the above servlet should be called. In this way you can have the logs getting printed in JSP.

Upvotes: 1

BalusC
BalusC

Reputation: 1108537

You're attempting to download a file by some code in a JSP file. JSP as being a view technology is actually the wrong tool for the job. Everything outside <% %> (which is normally text based content like HTML, XML, JSON, etc) is written to the HTTP response as well, including whitespace. This would only corrupt the integrity of the downloaded content which is written by Java code, even more so if you're serving binary files such as document/audio/video files.

Your concrete problem is caused because JSP internally uses response.getWriter() to print all the template content (everything outside <% %>) and then you're attempting to use getOutputStream(). This is an illegal state. You can't use them both simultaneously on a single response. Apart from using getWriter() instead, you could solve it by removing any whitespace outside <% %>, including newlines.

So, replace

<%@ page import="java.util.*,java.io.*"%>             

<%
    // Your Java code.
%>

by

<%@ page import="java.util.*,java.io.*"%><%
    // Your Java code.
%>

(and make absolutely sure that there's no trailing whitespace/newline after the last %> as well)

However, you should actually not be using JSP for the job. It's as said the wrong tool for the job. You should be using a normal HTTP servlet class for the job. Just create a class extending HttpServlet and move all the Java code which you've there in the JSP into the doGet() method. Finally map that servlet on an URL and invoke that URL instead.

@WebServlet("/download")
public class DownloadServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // Your Java code.
    }

}

You can find a more concrete example in this article.

See also:

Upvotes: 6

Ramesh PVK
Ramesh PVK

Reputation: 15446

You are getting the error because response.getWriter(); was already called before response.getOutputStream();. It is illegal to call both getWriter() and getOutputStream() in a service call. And JSP's, by default use getWriter() .

Try replacing

ServletOutputStream outs = response.getOutputStream(); 

with

PrintWriter outs = response.getWriter();

Upvotes: -1

Prateek
Prateek

Reputation: 551

  1. did you tried using "out" which is implicitly present on jsp?

  2. Does your program has permissions to read files from disk?

Thanks,
Prateek

Upvotes: -1

Related Questions