Servlets中的doGet和doPost方法

111

我开发了一个向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和password被设置为null。为什么在这种情况下我不能获得这些值?

另一个我想了解的事情是如何使用Servlet生成或验证的数据。例如,如果上面显示的Servlet对用户进行身份验证,我想要在我的HTML页面中打印用户ID。我应该能够发送字符串 'id' 作为响应并在我的HTML页面中使用该信息。这可能吗?


你如何在HTML中使用POST方法? - Igor Artamonov
还有,你为什么需要如此奇怪的参数名称循环? - Igor Artamonov
1
你尝试过移除 enctype=multipart/form-data 吗?我怀疑这可能是你的问题所在。 - Jack Leow
就是这样。为什么存在时post不起作用?感谢您的帮助! - dedalo
5个回答

207

介绍

当您想要拦截HTTP GET请求时,应使用doGet()。当您想要拦截HTTP POST请求时,应使用doPost()。就这样。不要将一个端口转移到另一个或反之亦然(例如在Netbeans的不幸自动生成的processRequest()方法中)。这毫无意义。

GET

通常情况下,HTTP GET请求是幂等的。也就是说,每次执行请求时都会得到完全相同的结果(不考虑授权/身份验证和页面的时效性--搜索结果、最新新闻等)。我们可以谈谈可书签化请求。点击链接、点击书签、在浏览器地址栏中输入原始URL等,都将触发HTTP GET请求。如果一个Servlet在相关的URL上监听,则它的doGet()方法将被调用。它通常用于预处理请求。也就是在呈现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>

POST

HTTP POST请求不具备幂等性。如果最终用户先前在URL上提交了一个POST表单,而该表单没有执行重定向,则该URL不一定是可书签的。提交的表单数据不会反映在URL中。将URL复制粘贴到新的浏览器窗口/标签页中可能不会产生与表单提交后完全相同的结果。这样的URL就不能被书签化。如果Servlet正在监听该URL,则将调用其doPost()方法。通常用于对请求进行后处理。即从提交的HTML表单中收集数据并对其进行一些业务处理(转换、验证、保存在数据库中等)。最终通常将结果作为来自转发的JSP页面的HTML呈现。

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

}

如果在数据库中找到User(即用户名和密码有效),则将User放入会话范围(即“已登录”),并将servlet重定向到某个主页(此示例转到http://example.com/contextname/home),否则它将设置错误消息并将请求转发回相同的JSP页面,以便通过${error}显示消息。

如果需要,您还可以将login.jsp“隐藏”在/WEB-INF/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实例变量——这是不安全的线程)。因此,我强烈建议学习一些基本的Java SE API,使用Oracle教程(查看“覆盖基础知识的路径”章节),以及如何正确使用JSP/Servlets使用这些教程

另请参阅:



更新:根据您问题的更新(这是相当重要的,您不应该删除原始问题的部分,否则答案将毫无价值..而是在新的块中添加信息),结果表明您不必将表单的编码类型设置为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()。另请参见此答案,其中包含一个具体示例:如何使用JSP/Servlet将文件上传到服务器?

3
GET 和 POST 都是浏览器用来向服务器请求单个资源的方法,每个资源都需要一个单独的 GET 或 POST 请求。GET 方法最常用(也是默认方法)用于从服务器检索信息。当使用 GET 方法时,请求包的第三部分——请求体——保持为空。
GET 方法有两种用法: 1. 当没有指定方法时,即当您或浏览器请求简单资源(如 HTML 页面、图像等)时。 2. 当表单被提交且在 HTML 的
标签上选择 method=GET 时。如果与 HTML 表单一起使用 GET 方法,则通过 URL 结尾添加“?”,然后添加所有名称=值对(HTML 表单字段的名称和输入该字段中的值)以“&”分隔的方式将通过表单收集到的数据发送到服务器。 示例: GET /sultans/shop//form1.jsp?name=Sam%20Sultan&iceCream=vanilla HTTP/1.0 可选标头可选标头<<空行>>
名称=值表单数据将存储在名为 QUERY_STRING 的环境变量中。该变量将被发送到处理程序(如 JSP、Java Servlet、PHP 等)。
POST 方法用于创建 HTML 表单,并在 标签中请求 method=POST。POST 方法允许客户端将表单数据发送到请求的请求体部分的服务器(如前面所述)。数据已编码并格式类似于 GET 方法,只是数据通过标准输入发送到程序。
示例: POST /sultans/shop//form1.jsp HTTP/1.0 可选标头可选标头<<空行>> name=Sam%20Sultan&iceCream=vanilla
使用 post 方法时,QUERY_STRING 环境变量将为空。 GET 和 POST 的优缺点 GET 方法的优点: 稍快 可以通过表单或在 URL 后附加参数输入参数 页面可以带有其参数的书签。
GET 方法的缺点: 只能发送 4K 的数据。 (当使用文本区域字段时不应使用它) 参数在 URL 结尾处可见。
POST 方法的优点: 参数不会在 URL 结尾处显示。 (用于敏感数据) 可以向服务器发送超过 4K 的数据
POST 方法的缺点: 不能与其数据一起进行书签。

1

Servlet容器对HttpServlet.service()方法的实现将自动转发到doGet()doPost(),因此您不需要覆盖service方法。


0
如果您在HTML表单中使用<form action="identification" >,数据将默认使用“Get”传递,因此您可以在Java Servlet代码中使用doGet函数捕获它。这样,数据将在HTML标头下传递,因此在提交后将在URL中可见。
另一方面,如果您想要在HTML正文中传递数据,则使用Post:<form action="identification" method="post">并在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");

.........
.........

0

你是不是通过get方式传递数据,而不是post方式?

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接