java - 从 jsp 页面调用时找不到 HTTPServlet
问题描述
我主要从事基于 jersey 的 web 服务,第一次尝试 jsp + servlet 组合,并在一些事情上苦苦挣扎
这是tomcat webapp文件夹中的目录结构:
├── 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>
下载Servlet
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(应该调用下载 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>");
}
我想要达到的目标:
本质上显示文件列表并将它们传递给下载 servlet 以触发下载。到目前为止,我能够让用户成功登录,但是当a
标签被触发时,我最终得到 404
也尝试了这个详尽的答案:
Servlet 返回“HTTP 状态 404 请求的资源 (/servlet) 不可用”
我尝试使用 servlet 直接访问浏览器,但仍然是 404。此外,href
参数正在发送到~:8080/download
它应该发送的时间~:8080/cti_dwnld/download/
任何指针/帮助表示赞赏!
解决方案
在<a> 标签中使用 servlet url-pattern 时无需使用前导 '\' 。如果您想使用 url-pattern /download调用您的 DownloadServlet,下面的代码可以正常工作
<a href='download?file=sample.txt'>Download</a>
请参阅下面的完整文件,其中文件名是动态的,我们通过用户请求从 JSP 获得,
小服务程序代码
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();
}
}
和JSP代码
<%@ 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>
我在这里使用了您共享的相同 web.xml 文件。
下面是目录结构,
操作系统版本:Windows 10 家庭版
Tomcat 版本:apache-tomcat-10.0.12
浏览器版本:Firefox 93.0(64 位)
推荐阅读
- java - 任务 ':app:kaptDebugKotlin' 执行失败。>
- javascript - 使用 ajax 调用用 div 标签替换 iframe 和框架
- laravel - 我在删除记录时收到此错误,详细问题如下。" 此路由不支持 GET 方法。支持的方法:POST。"
- html - 如何将文本限制为网格元素内的边界
- java - 启动chromedriver的进程终止时如何自动杀死chromedriver.exe?
- python - 特定整数的while循环(Python)
- tableau-api - 仅按年显示选定的月份(YTD)
- machine-learning - 有意义地解释 BaseN 编码的特征重要性
- validation - 在重复的工作表中复制受 Google 表格保护的范围 [解决方法]
- algorithm - 在两个排序序列之间找到共同元素的时间复杂度