且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Servlet中的doGet和doPost

更新时间:2023-12-04 14:36:53

简介



你应该使用 doGet() /rfc2616-sec9.html#sec9.3rel =noreferrer> HTTP GET请求。你应该使用 doPost() 当你想拦截 HTTP POST请求。就这样。不要将一个移植到另一个,反之亦然(例如在Netbeans的不幸的自动生成的 processRequest()方法中)。这没有任何意义。

Introduction

You should use doGet() when you want to intercept on HTTP GET requests. You should use doPost() when you want to intercept on HTTP POST requests. That's all. Do not port the one to the other or vice versa (such as in Netbeans' unfortunate auto-generated processRequest() method). This makes no utter sense.

通常,HTTP GET请求是幂等。即每次执行请求时都会得到完全相同的结果(保留授权/身份验证以及页面搜索结果的时间敏感性,最后新闻等 - 在考虑之外)。我们可以谈论可收藏的请求。单击链接,单击书签,在浏览器地址栏中输入原始URL,等等都将触发HTTP GET请求。如果Servlet正在侦听有问题的URL,那么将调用其 doGet()方法。它通常用于预处理请求。即在从JSP呈现HTML输出之前做一些业务,比如收集数据以便在表中显示。

Usually, HTTP GET requests are idempotent. I.e. you get exactly the same result everytime you execute the request (leaving authorization/authentication and the time-sensitive nature of the page —search results, last news, etc— outside consideration). We can talk about a bookmarkable request. Clicking a link, clicking a bookmark, entering raw URL in browser address bar, etcetera will all fire a HTTP GET request. If a Servlet is listening on the URL in question, then its doGet() method will be called. It's usually used to preprocess a request. I.e. doing some business stuff before presenting the HTML output from a JSP, such as gathering data for display in a table.

@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);
    }

}



<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>

同样查看/编辑上面最后一栏所示的详细链接通常是幂等的。

Also view/edit detail links as shown in last column above are usually idempotent.

@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>



POST



HTTP POST请求不是幂等。如果最终用户事先在URL上提交了POST表单(尚未执行重定向),则该URL不一定是可收藏的。提交的表单数据不会反映在URL中。将URL复制到新的浏览器窗口/选项卡可能不一定会产生与表单提交后完全相同的结果。这样的URL因此不可收藏。如果Servlet正在侦听有问题的URL,那么将调用其 doPost()。它通常用于后处理请求。即从提交的HTML表单中收集数据并用它做一些业务(转换,验证,保存在DB等)。最后,结果通常是转发的JSP页面中的HTML。

POST

HTTP POST requests are not idempotent. If the enduser has submitted a POST form on an URL beforehand, which hasn't performed a redirect, then the URL is not necessarily bookmarkable. The submitted form data is not reflected in the URL. Copypasting the URL into a new browser window/tab may not necessarily yield exactly the same result as after the form submit. Such an URL is then not bookmarkable. If a Servlet is listening on the URL in question, then its doPost() will be called. It's usually used to postprocess a request. I.e. gathering data from a submitted HTML form and doing some business stuff with it (conversion, validation, saving in DB, etcetera). Finally usually the result is presented as HTML from the forwarded JSP page.

<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结合使用:

...which can be used in combination with this piece of 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中找到用户(即用户名和密码有效),那么用户将被放入会话范围(即登录),servlet将重定向到某个主页面(此示例转到 http://example.com/contextname/home ),否则它将设置一条错误消息并将请求转发回同一个JSP页面,以便消息显示为 $ {error}

You see, if the User is found in DB (i.e. username and password are valid), then the User will be put in session scope (i.e. "logged in") and the servlet will redirect to some main page (this example goes to http://example.com/contextname/home), else it will set an error message and forward the request back to the same JSP page so that the message get displayed by ${error}.

您可以根据需要在 /WEB-INF/login.jsp $ c中隐藏 login.jsp $ c>以便用户只能通过servlet访问它。这样可以保持URL干净 http://example.com/contextname/login 。您需要做的就是向servlet添加一个 doGet(),如下所示:

You can if necessary also "hide" the login.jsp in /WEB-INF/login.jsp so that the users can only access it by the servlet. This keeps the URL clean http://example.com/contextname/login. All you need to do is to add a doGet() to the servlet like this:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
}

(并更新中的同一行> doPost()相应地)

(and update the same line in doPost() accordingly)

那就是说,我不确定它是不是只是玩耍而且在黑暗中拍摄,但是您发布的代码看起来不太好(例如使用 compareTo()而不是 equals()和挖掘参数名而不是仅使用 getParameter() id 密码似乎被声明为servlet实例变量—这不是线程)。因此,我强烈建议您使用 Oracle教程(基于Oracle教程)学习更多有关基本Java SE API的知识(查看Trails Covering the Basics一章以及如何使用以正确的方式使用JSP / Servlet那些教程

That said, I am not sure if it is just playing around and shooting in the dark, but the code which you posted doesn't look good (such as using compareTo() instead of equals() and digging in the parameternames instead of just using getParameter() and the id and password seems to be declared as servlet instance variables — which is NOT threadsafe). So I would strongly recommend to learn a bit more about basic Java SE API using the Oracle tutorials (check the chapter "Trails Covering the Basics") and how to use JSP/Servlets the right way using those tutorials.

  • Our servlets wiki page
  • Java EE web development, where do I start and what skills do I need?
  • Servlet returns "HTTP Status 404 The requested resource (/servlet) is not available"
  • Show JDBC ResultSet in HTML in JSP page using MVC and DAO pattern

更新:as根据你的问题的更新(这是非常重要的,你不应该删除原始问题的部分,这将使答案毫无价值......而不是在新的块中添加信息),事实证明您不必将表单的编码类型设置为 multipart / form-data 。这将以与(默认) application / x-www-form-urlencoded 不同的组合形式发送请求参数,该请求将请求参数作为查询字符串发送(例如 NAME1 =值1&安培; 2 =值2&安培; NAME3 =值3 )。只要你有一个< input type =file> 元素,你只需 multipart / form-data 上传文件的表格可能是非字符数据(二进制数据)。在您的情况下情况并非如此,因此只需将其删除即可按预期工作。如果您需要上传文件,那么您必须设置编码类型并自行解析请求体。通常你在那里使用 Apache Commons FileUpload ,但是如果你已经使用了全新的Servlet 3.0 API,然后你可以使用以 的HttpServletRequest#getPart() 。有关具体示例,请参阅此答案:如何使用JSP / Servlet将文件上传到服务器?

Update: as per the update of your question (which is pretty major, you should not remove parts of your original question, this would make the answers worthless .. rather add the information in a new block) , it turns out that you're unnecessarily setting form's encoding type to multipart/form-data. This will send the request parameters in a different composition than the (default) application/x-www-form-urlencoded which sends the request parameters as a query string (e.g. name1=value1&name2=value2&name3=value3). You only need multipart/form-data whenever you have a <input type="file"> element in the form to upload files which may be non-character data (binary data). This is not the case in your case, so just remove it and it will work as expected. If you ever need to upload files, then you'll have to set the encoding type so and parse the request body yourself. Usually you use the Apache Commons FileUpload there for, but if you're already on fresh new Servlet 3.0 API, then you can just use builtin facilities starting with HttpServletRequest#getPart(). See also this answer for a concrete example: How to upload files to server using JSP/Servlet?