简介
当你想拦截HTTP GET requests 时,你应该使用doGet()。当你想拦截HTTP POST requests 时,你应该使用doPost()。就这样。不要将一个移植到另一个,反之亦然(例如在 Netbeans 不幸的自动生成 processRequest() 方法中)。这完全没有意义。
获取
通常,HTTP GET 请求是idempotent。 IE。每次执行请求时都会得到完全相同的结果(将授权/身份验证和页面的时间敏感特性——搜索结果、最新消息等——排除在外)。我们可以讨论一个可收藏的请求。单击链接、单击书签、在浏览器地址栏中输入原始 URL 等都会触发 HTTP GET 请求。如果 Servlet 正在侦听相关 URL,则将调用其 doGet() 方法。它通常用于预处理请求。 IE。在呈现来自 JSP 的 HTML 输出之前做一些业务工作,例如收集数据以在表格中显示。
@WebServlet("/products")
public class ProductsServlet extends HttpServlet {
@EJB
private ProductService productService;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Product> products = productService.list();
request.setAttribute("products", products); // Will be available as ${products} in JSP
request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response);
}
}
请注意,JSP 文件显式放置在 /WEB-INF 文件夹中,以防止最终用户无需调用预处理 servlet 即可直接访问它(因此最终会因看到一个空表而感到困惑)。
<table>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.name}</td>
<td><a href="product?id=${product.id}">detail</a></td>
</tr>
</c:forEach>
</table>
此外,上面最后一列中显示的查看/编辑详细信息链接通常是幂等的。
@WebServlet("/product")
public class ProductServlet extends HttpServlet {
@EJB
private ProductService productService;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Product product = productService.find(request.getParameter("id"));
request.setAttribute("product", product); // Will be available as ${product} in JSP
request.getRequestDispatcher("/WEB-INF/product.jsp").forward(request, response);
}
}
<dl>
<dt>ID</dt>
<dd>${product.id}</dd>
<dt>Name</dt>
<dd>${product.name}</dd>
<dt>Description</dt>
<dd>${product.description}</dd>
<dt>Price</dt>
<dd>${product.price}</dd>
<dt>Image</dt>
<dd><img src="productImage?id=${product.id}" /></dd>
</dl>
发布
HTTP POST 请求不是幂等的。如果最终用户事先在 URL 上提交了 POST 表单,而该 URL 没有执行重定向,则该 URL 不一定是可收藏的。提交的表单数据不会反映在 URL 中。将 URL 复制粘贴到新的浏览器窗口/选项卡中可能不一定会产生与表单提交后完全相同的结果。这样一个 URL 就不能被收藏。如果 Servlet 正在侦听相关 URL,则将调用其 doPost()。它通常用于后处理请求。 IE。从提交的 HTML 表单中收集数据并用它做一些业务(转换、验证、保存在数据库中,等等)。最后,结果通常以 HTML 形式从转发的 JSP 页面呈现。
<form action="login" method="post">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" value="login">
<span class="error">${error}</span>
</form>
...可以和这段Servlet结合使用:
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@EJB
private UserService userService;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user);
response.sendRedirect("home");
}
else {
request.setAttribute("error", "Unknown user, please try again");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
}
你看,如果在 DB 中找到 User(即用户名和密码有效),那么 User 将被放入会话范围内(即“登录”),并且 servlet 将重定向到某个主页面(此示例转到http://example.com/contextname/home),否则它将设置错误消息并将请求转发回相同的JSP页面,以便${error}显示消息。
如有必要,您还可以在/WEB-INF/login.jsp 中“隐藏”login.jsp,以便用户只能通过 servlet 访问它。这使 URL 保持干净 http://example.com/contextname/login。您需要做的就是向 servlet 添加一个 doGet(),如下所示:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
}
(并相应地更新doPost() 中的同一行)
也就是说,我不确定它是否只是在黑暗中玩耍和射击,但是您发布的代码看起来不太好(例如使用compareTo()而不是equals()并挖掘参数名称而不是仅仅使用getParameter() 和id 和password 似乎被声明为servlet 实例变量——这不是threadsafe)。因此,我强烈建议您使用Oracle tutorials 了解更多有关基本 Java SE API 的信息(查看“Trails Covering the Basics”一章)以及如何使用 those tutorials 以正确的方式使用 JSP/Servlets。
另见:
更新:根据您的问题的更新(这是非常重要的,您不应该删除原始问题的部分内容,这会使答案变得毫无价值......而是添加 em> 新块中的信息),事实证明您不必要地将表单的编码类型设置为multipart/form-data。这将以不同于(默认)application/x-www-form-urlencoded 的组合发送请求参数,后者将请求参数作为查询字符串(例如name1=value1&name2=value2&name3=value3)发送。只要表单中有<input type="file"> 元素,您只需multipart/form-data 即可上传可能是非字符数据(二进制数据)的文件。您的情况并非如此,因此只需将其删除,它就会按预期工作。如果您需要上传文件,那么您必须设置编码类型并自己解析请求正文。通常你在那里使用Apache Commons FileUpload,但如果你已经在使用全新的Servlet 3.0 API,那么你可以使用以HttpServletRequest#getPart()开头的内置工具。另请参阅此答案以获取具体示例:How to upload files to server using JSP/Servlet?