《Servlet、JSP和Spring MVC初学指南》——2.2 隐藏域

2.2 隐藏域

使用隐藏域来保持状态类似于URL重写技术,但不是将值附加到URL上,而是放到HTML表单的隐藏域中。当表单提交时,隐藏域的值也同时提交到服务器端。隐藏域技术仅当网页有表单时有效。该技术相对于URL重写的优势在于:没有字符数限制,同时无须额外的编码。但该技术同URL重写一样,不适合跨越多个界面。

清单2.3展示了如何通过隐藏域来更新客户信息。清单2.2的Customer类为客户对象模型。

清单2.2 Customer类

package app02a.hiddenfields;
public class Customer {
    private int id;
    private String name;
    private String city;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
}

清单2.3 CustomerServlet类

package app02a.hiddenfields;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/*
 * Not thread-safe. For illustration purpose only
 */
@WebServlet(name = "CustomerServlet", urlPatterns = {
        "/customer", "/editCustomer", "/updateCustomer"})
public class CustomerServlet extends HttpServlet {
    private static final long serialVersionUID = -20L;

    private List<Customer> customers = new ArrayList<Customer>();

    @Override
    public void init() throws ServletException {
        Customer customer1 = new Customer();
        customer1.setId(1);
        customer1.setName("Donald D.");
        customer1.setCity("Miami");

        customers.add(customer1);

        Customer customer2 = new Customer();
        customer2.setId(2);
        customer2.setName("Mickey M.");
        customer2.setCity("Orlando");
        customers.add(customer2);
    }

    private void sendCustomerList(HttpServletResponse response)
            throws IOException {
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.println("<html><head><title>Customers</title></head>"
                + "<body><h2>Customers </h2>");
        writer.println("<ul>");
        for (Customer customer : customers) {
            writer.println("<li>" + customer.getName()
                   + "(" + customer.getCity() + ") ("
                   + "<a href='editCustomer?id=" + customer.getId()
                   + "'>edit</a>)");
        }
        writer.println("</ul>");
        writer.println("</body></html>");
    }

    private Customer getCustomer(int customerId) {
        for (Customer customer : customers) {
            if (customer.getId() == customerId) {
                return customer;
            }
        }
        return null;
    }

    private void sendEditCustomerForm(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        int customerId = 0;
        try {
            customerId =
                    Integer.parseInt(request.getParameter("id"));
        } catch (NumberFormatException e) {
        }
        Customer customer = getCustomer(customerId);

        if (customer != null) {
            writer.println("<html><head>"
                    + "<title>Edit Customer</title></head>"
                    + "<body><h2>Edit Customer</h2>"
                    + "<form method='post' "
                    + "action='updateCustomer'>");
            writer.println("<input type='hidden' name='id' value='"
                    + customerId + "'/>");
            writer.println("<table>");
            writer.println("<tr><td>Name:</td><td>"
                    + "<input name='name' value='" +
                    customer.getName().replaceAll("'", "'")
                    + "'/></td></tr>");
            writer.println("<tr><td>City:</td><td>"
                    + "<input name='city' value='" +
                    customer.getCity().replaceAll("'", "'")
                    + "'/></td></tr>");
            writer.println("<tr>"
                    + "<td colspan='2' style='text-align:right'>"
                    + "<input type='submit' value='Update'/></td>"
                    + "</tr>");
            writer.println("<tr><td colspan='2'>"
                    + "<a href='customer'>Customer List</a>"
                    + "</td></tr>");
            writer.println("</table>");
            writer.println("</form></body>");
        } else {
            writer.println("No customer found");
        }

    }
    @Override
    public void doGet(HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException {
        String uri = request.getRequestURI();
        if (uri.endsWith("/customer")) {
            sendCustomerList(response);
        } else if (uri.endsWith("/editCustomer")) {
            sendEditCustomerForm(request, response);
        }
    }

    @Override
    public void doPost(HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException {
        // update customer
        int customerId = 0;
        try {
            customerId =
                    Integer.parseInt(request.getParameter("id"));
        } catch (NumberFormatException e) {
        }
        Customer customer = getCustomer(customerId);
        if (customer != null) {
            customer.setName(request.getParameter("name"));
            customer.setCity(request.getParameter("city"));
        }
        sendCustomerList(response);
    }
}

CustomerServlet类继承自HttpServlet,其URL映射分别为/customer、/editCustomer和 /updateCustomer。前两个URL会调用Servlet的doGet方法,而/updateCustomer 会调用doPost方法。

/customer是本例的入口URL。该URL会列举出在init 方法中所初始化的类级别的列表对象customers(在真实应用中,通常是从数据库中获取用户信息),如图2.4所示。

图2.4 客户列表

如图2.4所示,每个客户信息后都有一个edit链接,每个edit链接的href属性为 /editCustomer? id=customerId。当通过/editCustomer访问servlet时,servlet会返回一个编辑表单,如图2.5所示。

图2.5 客户编辑表单

如果你点击的是第一个客户,servlet返回表单中的隐藏域如下:

<form method='post' action='updateCustomer'>
<input type='hidden' name='id' value='1'/>
<table>
    <tr><td>Name:</td>
    <td><input name='name' value='Donald DC.'/></td>
</tr>
<tr>
    <td>City:</td><td><input name='city' value='Miami'/></td>
</tr>
<tr>
    <td colspan='2' style='text-align:right'>
        <input type='submit' value='Update'/>
    </td>
</tr>
<tr>
    <td colspan='2'><a href='customer'>Customer List</a></td>
</tr>
</table>
</form>

该隐藏域为所编辑的客户id,因此当表单提交时,服务端就知道应更新哪个客户信息。

需要强调的是,表单是通过post方式提交的,因此调用的是servlet的doPost方法。

时间: 2024-10-26 05:38:21

《Servlet、JSP和Spring MVC初学指南》——2.2 隐藏域的相关文章

《Servlet、JSP和Spring MVC初学指南》——导读

前言 Java Servlet技术简称Servlet技术,是Java开发Web应用的底层技术.由Sun公司于1996年发布,用来代替CGI--当时生成Web动态内容的主流技术.CGI技术的主要问题是每个Web请求都需要新启动一个进程来处理.创建进程会消耗不少CPU周期,导致难以编写可扩展的CGI程序.而Servlet有着比CGI程序更好的性能,因为Servlet在创建后(处理第一个请求时)就一直保持在内存中.此后,SUN公司发布了JavaServer Pages(JSP)技术,以进一步简化ser

《Servlet、JSP和Spring MVC初学指南》——1.3 编写基础的Servlet应用程序

1.3 编写基础的Servlet应用程序 其实,编写Servlet应用程序出奇简单.只需要创建一个目录结构,并把Servlet类放在某个目录下.本节将教你如何编写一个名为app01a的Servlet应用程序.最初,它会包含一个Servlet,即MyServlet,其效果是向用户发出一条问候. 要运行Servlets,还需要一个Servlet容器.Tomcat是一个开源的Servlet容器,它是免费的,并且可以在任何能跑Java的平台上运行.如果你到现在都还没有安装Tomcat,就应该去看看附录A

《Servlet、JSP和Spring MVC初学指南》——2.4 HttpSession对象

2.4 HttpSession对象 在所有的会话跟踪技术中,HttpSession 对象是最强大和最通用的.一个用户可以有且最多有一个HttpSession,并且不会被其他用户访问到. HttpSession对象在用户第一次访问网站的时候自动被创建,你可以通过调用HttpServletRequest的getSession方法获取该对象.getSession有两个重载方法: HttpSession getSession() HttpSession getSession(boolean create

《Servlet、JSP和Spring MVC初学指南》——2.3 Cookies

2.3 Cookies URL重写和隐藏域仅适合保存无须跨越太多页面的信息.如果需要在多个页面间传递信息,则以上两种技术实现成本高昂,因为你不得不在每个页面都进行相应处理.幸运的是,Cookies技术可以帮助我们. Cookies是一个很少的信息片段,可自动地在浏览器和Web服务器间交互,因此cookies可存储在多个页面间传递的信息.Cookie作为HTTP header的一部分,其传输由HTTP协议控制.此外,你可以控制cookies的有效时间.浏览器通常支持每个网站高达20个cookies

《Servlet、JSP和Spring MVC初学指南》——1.10 处理HTML表单

1.10 处理HTML表单 一个Web应用程序中几乎总会包含一个或者多个HTML表单,供用户输入值.你可以轻松地将一个HTML表单从一个Servlet发送到浏览器.当用户提交表单时,在表单元素中输入的值就会被当作请求参数发送到服务器. HTML输入域(文本域.隐藏域或者密码域)或者文本区的值,会被当作字符串发送到服务器.空的输入域或者文本区会发送空的字符串.因此,有输入域名称的,ServletRequest.getParameter绝对不会返回null. HTML的select元素也向heade

《Servlet、JSP和Spring MVC初学指南》——1.11 使用部署描述符

1.11 使用部署描述符 如在前面的例子中所见,编写和部署Servlet都是很容易的事情.部署的一个方面是用一个路径配置Servlet的映射.在这些范例中,是利用WebServlet标注类型,用一个路径映射了一个Servlet. 利用部署描述符是配置Servlet应用程序的另一种方法,部署描述符的详情将在第13章"部署描述符"中探讨.部署描述符总是命名为web.xml,并且放在WEB-INF目录下.本章介绍了如何创建一个名为app01c的Servlet应用程序,并为它编写了一个web.

《Servlet、JSP和Spring MVC初学指南》——1.6 ServletConfig

1.6 ServletConfig 当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init方法传入一个ServletConfig.ServletConfig封装可以通过@WebServlet或者部署描述符传给Servlet的配置信息.这样传入的每一条信息就叫一个初始参数.一个初始参数有key和value两个元件. 为了从Servlet内部获取到初始参数的值,要在Servlet容器传给Servlet的init方法的ServletConfig中调用getInitP

《Servlet、JSP和Spring MVC初学指南》——1.9 Http Servlets

1.9 Http Servlets 不说全部,至少大多数应用程序都要与HTTP结合起来使用.这意味着可以利用HTTP提供的特性.javax.servlet.http包是Servlet API中的第二个包,其中包含了用于编写Servlet应用程序的类和接口.javax.servlet.http中的许多类型都覆盖了javax.servlet中的类型. 图1.5展示了javax.servlet.http中的主要类型. 图1.5 javax.servlet.http中的主要类型 1.9.1 HttpSe

《Servlet、JSP和Spring MVC初学指南》——1.4 ServletRequest

1.4 ServletRequest 对于每一个HTTP请求,Servlet容器都会创建一个ServletRequest实例,并将它传给Servlet的Service方法.ServletRequest封装了关于这个请求的信息. ServletRequest接口中有一些方法. public int getContentLength() 返回请求主体的字节数.如果不知道字节长度,这个方法就会返回−1. public java.lang.String getContentType() 返回请求主体的M