【问题标题】:doGet and doPost in ServletsServlet 中的 doGet 和 doPost
【发布时间】:2011-01-21 22:05:36
【问题描述】:

我开发了一个向 Servlet 发送信息的 HTML 页面。在 Servlet 中,我使用了 doGet()doPost() 方法:

public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException  {

     String id = req.getParameter("realname");
     String password = req.getParameter("mypassword");
}

public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {

    String id = req.getParameter("realname");
    String password = req.getParameter("mypassword");
}

在调用Servlet的html页面代码是:

<form action="identification" method="post" enctype="multipart/form-data">
    User Name: <input type="text" name="realname">
    Password: <input type="password" name="mypassword">
    <input type="submit" value="Identification">
</form> 

当我在 Servlet 中使用 method = "get" 时,我得到了 id 和 password 的值,但是当使用 method = "post" 时,id 和密码设置为 null。为什么在这种情况下我没有得到值?

我想知道的另一件事是如何使用由 Servlet 生成或验证的数据。例如,如果上面显示的 Servlet 对用户进行身份验证,我想在我的 HTML 页面中打印用户 ID。我应该能够发送字符串“id”作为响应,并在我的 HTML 页面中使用此信息。有可能吗?

【问题讨论】:

  • 你是如何在 html 中使用 post 方法的?
  • 还有,你需要什么奇怪的参数名称循环?
  • 您是否尝试过删除`enctype=multipart/form-data`?我怀疑这是你的问题。
  • 就是这样。为什么存在时不发布工作?感谢您的帮助!

标签: java servlets


【解决方案1】:

简介

当你想拦截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()idpassword 似乎被声明为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&amp;name2=value2&amp;name3=value3)发送。只要表单中有&lt;input type="file"&gt; 元素,您只需multipart/form-data 即可上传可能是非字符数据(二进制数据)的文件。您的情况并非如此,因此只需将其删除,它就会按预期工作。如果您需要上传文件,那么您必须设置编码类型并自己解析请求正文。通常你在那里使用Apache Commons FileUpload,但如果你已经在使用全新的Servlet 3.0 API,那么你可以使用以HttpServletRequest#getPart()开头的内置工具。另请参阅此答案以获取具体示例:How to upload files to server using JSP/Servlet?

【讨论】:

    【解决方案2】:

    servlet 容器对HttpServlet.service() 方法的实现会根据需要自动转发到doGet()doPost(),因此您不需要重写服务方法。

    【讨论】:

      【解决方案3】:

      如果您为您的 html 表单执行 &lt;form action="identification" &gt;,默认情况下将使用“Get”传递数据,因此您可以在您的 java servlet 代码中使用 doGet 函数来捕获它。这样,数据将在 HTML 标头下传递,因此在提交时将在 URL 中可见。 另一方面,如果您想在 HTML 正文中传递数据,则使用 Post:&lt;form action="identification" method="post"&gt; 并在 doPost 函数中捕获此数据。也就是说,数据将在 html 正文而不是 html 标头下传递,提交表单后您将看不到 URL 中的数据。

      我的 html 中的示例:

      <body>  
      <form action="StartProcessUrl" method="post">
      .....
      .....
      

      来自我的 java servlet 代码的示例:

      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // TODO Auto-generated method stub
              PrintWriter out = response.getWriter();
               String surname = request.getParameter("txtSurname");
               String firstname = request.getParameter("txtForename");
               String rqNo = request.getParameter("txtRQ6");
               String nhsNo = request.getParameter("txtNHSNo");
      
               String attachment1 = request.getParameter("base64textarea1");
               String attachment2 = request.getParameter("base64textarea2");
      
      .........
      .........
      

      【讨论】:

        【解决方案4】:

        浏览器使用 GET 和 POST 从服务器请求单个资源。每个资源都需要一个单独的 GET 或 POST 请求。

        1. GET 方法是浏览器从服务器检索信息最常用的方法(也是默认方法)。使用 GET 方法时,请求包的第 3 部分,即请求正文,保持为空。

        GET 方法以两种方式之一使用: 当没有指定方法时,即您或浏览器正在请求一个简单的资源,例如 HTML 页面、图像等。 提交表单时,您在 HTML 标记上选择 method=GET。如果 GET 方法与 HTML 表单一起使用,则通过表单收集的数据通过附加“?”发送到服务器。到 URL 的末尾,然后添加由“&”分隔的所有名称=值对(html 表单字段的名称和在该字段中输入的值) 例子: GET /sultans/shop//form1.jsp?name=Sam%20Sultan&iceCream=vanilla HTTP/1.0 optional header optional header>>

        name=value 表单数据将存储在名为 QUERY_STRING 的环境变量中。 这个变量将被发送到一个处理程序(如JSP、Java servlet、PHP等)

        1. 创建 HTML 表单时使用 POST 方法,并且请求方法=POST 作为标记的一部分。 POST 方法允许客户端在请求的请求正文部分向服务器发送表单数据(如前所述)。数据经过编码和格式化,类似于 GET 方法,只是数据是通过标准输入发送到程序的。

        示例: POST /sultans/shop//form1.jsp HTTP/1.0 optional header optional header>> name=Sam%20Sultan&iceCream=vanilla

        使用 post 方法时,QUERY_STRING 环境变量将为空。 GET 与 POST 的优缺点

        GET方法的优点: 稍微快一点 可以通过表单输入参数,也可以在 URL 后面附加参数 页面可以使用其参数添加书签

        GET方法的缺点: 只能发送 4K 的数据。 (使用 textarea 字段时不应使用它) 参数在 URL 的末尾可见

        POST方法的优点: 参数在 URL 的末尾不可见。 (用于敏感数据) 可以向服务器发送超过 4K 的数据

        POST方法的缺点: 不能用其数据添加书签

        【讨论】:

          【解决方案5】:

          可能是您通过 get 而不是 post 传递数据?

          <form method="get" ..>
          ..
          </form>
          

          【讨论】:

            猜你喜欢
            • 2012-02-27
            • 2011-07-09
            • 2011-08-18
            • 2014-05-23
            • 1970-01-01
            • 2015-04-01
            • 2014-06-02
            • 1970-01-01
            • 2017-04-19
            相关资源
            最近更新 更多