0

I have mostly worked on jersey based webservices, trying my hand on jsp + servlet combo for the first time and struggling a lot with few things

here is what the directory structures looks likes in tomcat webapp folder:

├── 403.jsp
├── META-INF
│   ├── MANIFEST.MF
│   ├── maven
│   │   └── com.csx.cti             <-----package
│   │       └── cti_dwnld           <-----project name
│   │           ├── pom.properties
│   │           └── pom.xml
│   └── war-tracker
├── WEB-INF
│   ├── classes
│   │   └── com
│   │       └── csx
│   │           └── cti
│   │               └── servlet
│   │                   └── DownloadServlet.class.   <----- servlet in question
│   ├── lib
│   │   ├── javax.servlet-api-3.0.1.jar
│   │   └── javax.ws.rs-api-2.1.1.jar
│   └── web.xml
├── error.jsp
├── index.jsp
├── login.jsp
└── logout.jsp

web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <display-name>Login Demo Using j_security_check</display-name>
    <!--Defines Security Constraint -->
    <security-constraint>
        <display-name>JSP Demo Constraint</display-name>
        <web-resource-collection>
            <web-resource-name>cp</web-resource-name>
            <description/>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>file-user</role-name>
        </auth-constraint>
    </security-constraint>
    <!--Defines Login Config -->
    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>cti file user realm</realm-name>
        <form-login-config>
            <form-login-page>/login.jsp</form-login-page>
            <form-error-page>/403.jsp</form-error-page>
        </form-login-config>
    </login-config>
    <!--Defines Security Role -->
    <security-role>
        <description/>
        <role-name>file-user</role-name>
    </security-role>
    <error-page>
        <error-code>403</error-code>
        <location>/403.jsp</location>
    </error-page>
</web-app>

DownloadServlet


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

//    private static final long serialVersionUID = 1L;

    private static final long serialVersionUID = 102831973239L;

    private static final int BYTES_DOWNLOAD = 1024;

    public DownloadServlet() {
        super();
    }

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

        // skip url params and use hardcode for now
        response.setContentType("text/plain");
        response.setHeader("Content-Disposition", "attachment;filename=sample.txt");
        ServletContext ctx = getServletContext();
        InputStream is = ctx.getResourceAsStream("sample.txt");

        int read = 0;
        byte[] bytes = new byte[BYTES_DOWNLOAD];
        OutputStream os = response.getOutputStream();

        while ((read = is.read(bytes)) != -1) {
            os.write(bytes, 0, read);
        }
        os.flush();
        os.close();
    }


    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
    }
}

index.jsp ( part which is supposed to call the download servlet )

      // l_Files is list of all files in the folder
      for (int a = 0; a < l_Files.size(); a++) {
          // have tried:
          // href='./download'
          // href='/download'
          // href='download'
          // href='/cti_dwnld/download'
          out.println("<a href='/download?file=sample.txt'>" + l_Files.elementAt(a).toString() + "</a><br>");
      }

What i am trying to achieve:

Essentially show a list of files and pass them to download servlet to trigger a download. So far i am able to get user successfully logged in but when a tag is triggered, i end up getting 404

as below

tried this exhaustive answer as well:

Servlet returns "HTTP Status 404 The requested resource (/servlet) is not available"

I tried directly hitting the browser with servlet but still 404. Also, the href param is sending to ~:8080/download when it should have been ~:8080/cti_dwnld/download/

any pointers / help is appreciated!

NoobEditor
  • 15,563
  • 19
  • 81
  • 112

1 Answers1

0

There is no need to use leading '\' while using servlet url-pattern in <a> tag. Below code is working fine if you want to call your DownloadServlet with url-pattern /download

<a href='download?file=sample.txt'>Download</a>

See the complete files below where file name is dynamic which we got from JSP via user request,

Servlet Code

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import jakarta.servlet.ServletContext;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

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

    private static final long serialVersionUID = 102831973239L;
    private static final int BYTES_DOWNLOAD = 1024;

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/plain");
        
        /**
         * Get name of the file dynamically from user request
         */
        String fileName = request.getParameter("file");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        ServletContext ctx = getServletContext();
        
        /**
         * Open stream to read the file, here file will be expected to be in root directory of the project
         */
        InputStream is = ctx.getResourceAsStream(fileName);
        int read = 0;
        byte[] bytes = new byte[BYTES_DOWNLOAD];
        OutputStream os = response.getOutputStream();

        while ((read = is.read(bytes)) != -1) {
            os.write(bytes, 0, read);
        }
        os.flush();
        os.close();
    }

}

And JSP code

<%@ page import="java.util.Vector"%>
<!DOCTYPE html>
<html>
<head>
<title>Index Page</title>
</head>
<body>

    <%
    //TODO: Please replace below code with your actual code to populate file names dynamically.
    Vector<String> l_Files = new Vector<String>();
    l_Files.add("sample1.txt");
    l_Files.add("sample2.txt");
    l_Files.add("sample3.txt");
    l_Files.add("sample4.txt");
    l_Files.add("sample5.txt");

    // l_Files is list of all files in the folder
    for (int a = 0; a < l_Files.size(); a++) { %>
         <a href='download?file=<%=l_Files.elementAt(a).toString() %>'><%=l_Files.elementAt(a).toString() %></a><br>
    <%
    }
    %>
</body>
</html>

I have used same web.xml file shared by you here.

Below is the directory structure,

enter image description here

OS Version : Windows 10 Home Edition

Tomcat Version : apache-tomcat-10.0.12

Browser Version : Firefox 93.0 (64-bit)

  • i get `This site can’t be reached` when trying this way. have you replicated the setup and it works for u? if so, can u tell me the os u r on and tomcat version? – NoobEditor Oct 21 '21 at 16:21
  • @NoobEditor I have updated my answer with the code and required details. Here I am able to download files successfully. Please note that I have added sample code in JSP file to create collection of files to be displayed to users for download, you need to replace with your code to populate the file names. – kody-technolab Oct 22 '21 at 06:40