客户请求的处理:表单数据

常常会看到这样的URL:http://host/path?user=Marty+Hall&origin=bwi&dest=sfo

它是服务器程序从web页面获取信息的最常见形式----表单数据跟在url后,GET请求即采用这种形式,表单数据也可以在单独的行里发送(POST请求)


topics:

单个请求参数的读取

全部请求参数的读取

缺失和异常数据的处理

过滤请求参数中的特殊字符

用请求参数的值自动填充数据对象

表单提交不完整的应付




1,在servlet中读取表单数据

1)单个值的读取getParameter

request.getParameter("Param1"),不管数据是由GET发送(即在doGET中)还是在doPOST中,都可以这样用。

如果参数存在但没有相应的值返回空的String,如果没有这个参数返回null。


2)多个值的读取getParameterValues,

public String[] getParameterValues(String name);

 通过一个String对象的数组返回指定参数的值,如果这个参数不存在,该方法返回一个空值。返回字符串的数组,同一个参数在表单数据中出现多次,返回字符串的数组。

一般情况下你应避免html表单参数名的重复,(这样就直接用getParameter即可)。但在某些情况下这无可避免,例如在多选列表框中,会为列表框中每个选定的元素重复使用参数名。


3) 参数名的查找getParameterNames 和getParameterMap

public Enumeration getParameterNames();

 返回所有参数名的String对象列表,如果没有输入参数,该方法返回一个空值。

public java.util.Map getParameterMap()
Returns a java.util.Map of the parameters of this request


4)原始表单数据的读取及对上载文件的分析:getReader 或 getInputStream  了解

两种情况下需要读取原始参数:数据不是html表单提交;数据来自于上载的文件


5)多字符集输入的读取:setCharacterEncoding  了解

request.getParameter使用服务器当前的字符集解释输入,要改变这种默认行为,需要使用setCharacterEncoding方法来设置字符集。但是如果输入中使用了多个字符集怎么办,这里提供一种参考的解决方案:

先读取感兴趣的参数,使用getBytes提取原始数据,然后转换为其他的字符集

String firstNameWrongEncoding = request.getParameter("firstName");
String firstName =
new String(firstNameWrongEncoding.getBytes(), "Shift_JIS");

2,示例:读取3个参数

表单:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML><HEAD><TITLE>Collecting Three Parameters</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H1 ALIGN="CENTER">Collecting Three Parameters</H1>


<FORM ACTION="/Servlet/servlet/ThreeParams">
  First Parameter:  <INPUT TYPE="TEXT" NAME="param1"><BR>
  Second Parameter: <INPUT TYPE="TEXT" NAME="param2"><BR>
  Third Parameter:  <INPUT TYPE="TEXT" NAME="param3"><BR>

  <CENTER><INPUT TYPE="SUBMIT"></CENTER>
</FORM>

</BODY></HTML>

响应的servlet:

package coreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;


public class ThreeParams extends HttpServlet {
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    String title = "Reading 1111 Three Request Parameters";
    String docType =
      "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
      "Transitional//EN\">\n";
    out.println(docType +
                "<HTML>\n" +
                "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" +
                "<BODY BGCOLOR=\"#FDF5E6\">\n" +
                "<H1 ALIGN=\"CENTER\">" + title + "</H1>\n" +
                "<UL>\n" +
                "  <LI><B>param1</B>: "
                + request.getParameter("param1") + "\n" +//读取参数
                "  <LI><B>param2</B>: "
                + request.getParameter("param2") + "\n" +
                "  <LI><B>param3</B>: "
                + request.getParameter("param3") + "\n" +
                "</UL>\n" +
                "</BODY></HTML>");
  }
}

路径问题:!!!

新建的一个Servlet的web项目:

建好后工程的域名就在http://localhost:8080/Servlet/下   !!!

src下的资源文件,都在web.xml里面可以查到映射的url,填在http://localhost:8080/Servlet/之后即可  !!!

在WebRoot下建的form文件夹下的html文件的路径是:http://localhost:8080/Servlet/form/1.html  !!!

在ACTION里的响应处理文件的servlet路径---工程名+映射的url:ACTION="/Servlet/servlet/ThreeParams"  !!!


3,读取所有参数

获取全部参数:

Enumeration paramNames = request.getParameterNames();

得到所有参数和参数值:

1 while(paramNames.hasMoreElements()) {
2 String paramName = (String)paramNames.nextElement();
3
4 String[] paramValues =
5 request.getParameterValues(paramName);

下面是全部的代码:

表单html:

1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2  <HTML><HEAD><TITLE>A Sample FORM using POST</TITLE></HEAD>
3  <BODY BGCOLOR="#FDF5E6">
4  <H1 ALIGN="CENTER">A Sample FORM using POST</H1>
5  <FORM ACTION="/servlet/coreservlets.ShowParameters"
6 METHOD="POST">
7 Item Number: <INPUT TYPE="TEXT" NAME="itemNum"><BR>
8 Description: <INPUT TYPE="TEXT" NAME="description"><BR>
9 Price Each: <INPUT TYPE="TEXT" NAME="price" VALUE="$"><BR>
10 <HR>
11
12 First Name: <INPUT TYPE="TEXT" NAME="firstName"><BR>
13 Last Name: <INPUT TYPE="TEXT" NAME="lastName"><BR>
14 Middle Initial: <INPUT TYPE="TEXT" NAME="initial"><BR>
15 Shipping Address:
16 <TEXTAREA NAME="address" ROWS=3 COLS=40></TEXTAREA><BR>
17 Credit Card:<BR>
18 &nbsp;&nbsp;<INPUT TYPE="RADIO" NAME="cardType"
19 VALUE="Visa">Visa<BR>
20
21 &nbsp;&nbsp;<INPUT TYPE="RADIO" NAME="cardType"
22 VALUE="MasterCard">MasterCard<BR>
23 &nbsp;&nbsp;<INPUT TYPE="RADIO" NAME="cardType"
24 VALUE="Amex">American Express<BR>
25 &nbsp;&nbsp;<INPUT TYPE="RADIO" NAME="cardType"
26 VALUE="Discover">Discover<BR>
27 &nbsp;&nbsp;<INPUT TYPE="RADIO" NAME="cardType"
28 VALUE="Java SmartCard">Java SmartCard<BR>
29 Credit Card Number:
30 <INPUT TYPE="PASSWORD" NAME="cardNum"><BR>
31 Repeat Credit Card Number:
32 <INPUT TYPE="PASSWORD" NAME="cardNum"><BR><BR>
33
34 <CENTER><INPUT TYPE="SUBMIT" VALUE="Submit Order"></CENTER>
35  </FORM>
36  </BODY></HTML>

响应servlet:

1 package coreservlets;
2
3  import java.io.*;
4  import javax.servlet.*;
5  import javax.servlet.http.*;
6  import java.util.*;
7
8
9
10  public class ShowParameters extends HttpServlet {
11 public void doGet(HttpServletRequest request,
12 HttpServletResponse response)
13 throws ServletException, IOException {
14 response.setContentType("text/html");
15 PrintWriter out = response.getWriter();
16 String docType =
17 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
18 "Transitional//EN\">\n";
19 String title = "Reading All Request Parameters";
20 out.println(docType +
21 "<HTML>\n" +
22 "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" +
23 "<BODY BGCOLOR=\"#FDF5E6\">\n" +
24 "<H1 ALIGN=CENTER>" + title + "</H1>\n" +
25 "<TABLE BORDER=1 ALIGN=CENTER>\n" +
26 "<TR BGCOLOR=\"#FFAD00\">\n" +
27 "<TH>Parameter Name<TH>Parameter Value(s)");
28 //关键代码
29   Enumeration paramNames = request.getParameterNames();
30 while(paramNames.hasMoreElements()) {
31 String paramName = (String)paramNames.nextElement();
32 out.print("<TR><TD>" + paramName + "\n<TD>");
33 String[] paramValues =
34 request.getParameterValues(paramName);
35 if (paramValues.length == 1) {
36 String paramValue = paramValues[0];
37 if (paramValue.length() == 0)
38 out.println("<I>No Value</I>");
39 else
40 out.println(paramValue);
41 } else {
42 out.println("<UL>");
43 for(int i=0; i<paramValues.length; i++) {
44 out.println("<LI>" + paramValues[i]);
45 }
46 out.println("</UL>");
47 }
48 }
49 out.println("</TABLE>\n</BODY></HTML>");
50 }
51
52 public void doPost(HttpServletRequest request,
53 HttpServletResponse response)
54 throws ServletException, IOException {
55 doGet(request, response);//注意html中是post方法!!!
56   }
57 }

提交表单后的结果:

4,参数确实或异常时默认值的应用

在用户提交表单时如果有的项没有填写,怎么解决:1)使用默认值。2)提示重新填写

这里解决1.

编写一些函数来处理缺省时的值,比如:

1 String name = request.getParameter("name");
2 name = replaceIfMissing(name, "Lou Zer");

在得到参数值后,在编写一个如果缺失的情况,使得如果不缺失name保持不变,缺失则替换为一个默认值。。举例略

5,过滤字符串中的html特殊字符

如果servlet希望生成含有<,>等字符的html,就要使用标准的html字符实体来代换这些符号,---

&lt---     <

&gt---    >

&quot---    "

&amp---    &

因为这些符号可能被解释为html属性的结尾。

可以先编写一个过滤的类

1 package coreservlets;
2
3  import javax.servlet.*;
4  import javax.servlet.http.*;
5
6
7
8  public class ServletUtilities {
9 public static final String DOCTYPE =
10 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
11 "Transitional//EN\">";
12
13
14 public static String headWithTitle(String title) {
15 return(DOCTYPE + "\n" +
16 "<HTML>\n" +
17 "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n");
18 }
19
20
21 public static int getIntParameter(HttpServletRequest request,
22 String paramName,
23 int defaultValue) {
24 String paramString = request.getParameter(paramName);
25 int paramValue;
26 try {
27 paramValue = Integer.parseInt(paramString);
28 } catch(NumberFormatException nfe) { // null or bad format
29   paramValue = defaultValue;
30 }
31 return(paramValue);
32 }
33
34 public static double getDoubleParameter
35 (HttpServletRequest request,
36 String paramName,
37 double defaultValue) {
38 String paramString = request.getParameter(paramName);
39 double paramValue;
40 try {
41 paramValue = Double.parseDouble(paramString);
42 } catch(NumberFormatException nfe) { // null or bad format
43   paramValue = defaultValue;
44 }
45 return(paramValue);
46 }
47
48
49  //将输入中的特殊字符替换后返回的静态方法
50  
51 public static String filter(String input) {
52 if (!hasSpecialChars(input)) {
53 return(input);
54 }
55 StringBuffer filtered = new StringBuffer(input.length());
56 char c;
57 for(int i=0; i<input.length(); i++) {
58 c = input.charAt(i);
59 switch(c) {
60 case '<': filtered.append("&lt;"); break;
61 case '>': filtered.append("&gt;"); break;
62 case '"': filtered.append("&quot;"); break;
63 case '&': filtered.append("&amp;"); break;
64 default: filtered.append(c);
65 }
66 }
67 return(filtered.toString());
68 }
69
70  //判断是否有特殊字符
71   private static boolean hasSpecialChars(String input) {
72 boolean flag = false;
73 if ((input != null) && (input.length() > 0)) {
74 char c;
75 for(int i=0; i<input.length(); i++) {
76 c = input.charAt(i);
77 switch(c) {
78 case '<': flag = true; break;
79 case '>': flag = true; break;
80 case '"': flag = true; break;
81 case '&': flag = true; break;
82 }
83 }
84 }
85 return(flag);
86 }
87 }

在servlet中可以过滤这个字符串然后输出!!!

6,根据请求参数自动填充java对象:表单bean

由于getParameter返回值是String,所以如果希望得到其他类型的值,转型比较麻烦,在jsp中,使用javabean组件可以极大地简化读取的请求参数。

(jsp页面实质上也是servlet),每个jsp页面都要转换成servlet,在请求运行期间执行的是servlet。在复杂的情况下,一般都是用jsp和servlet组合,servlet完成编程任务而jsp完成表示任务。

jsp提供了javabean,但servlet却并没有实现这种读取参数的方法。不过,apache基金会的Jakarta通用包提供了这样的类,使得我们可以更容易的构建自动请求参数和bean属性关联起来。它的BeanUtilities类下提供了这样的静态方法:

public static void populateBean(Object bean, Map propertyMap)

将map中的所有值传递给bean中与相关的map键名匹配的属性

调用方法:

public static void populateBean(Object formBean,
                                  HttpServletRequest request) {
    populateBean(formBean, request.getParameterMap());
  }

即可完成请求参数到一个bean的自动填充。

1 package coreservlets.beans;
2
3  import java.util.*;
4  import javax.servlet.http.*;
5  import org.apache.commons.beanutils.BeanUtils;
6
7
8  public class BeanUtilities {
9
10
11 public static void populateBean(Object formBean,
12 HttpServletRequest request) {
13  //从request得到一个map,调用后面的方法来填充
14   populateBean(formBean, request.getParameterMap());
15 }
16
17
18 //map到bean的填充方法
19   public static void populateBean(Object bean,
20 Map propertyMap) {
21 try {
22 BeanUtils.populate(bean, propertyMap);
23 } catch(Exception e) {
24
25 }
26 }
27 }

示例:

表单:

View Code
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2  <!--
3 Front end to InsuranceInfo servlet. Note that the names of
4 the form parameters here *must* match the names of the bean
5 properties.
6
7 Taken from Core Servlets and JavaServer Pages 2nd Edition
8 from Prentice Hall and Sun Microsystems Press,
9 http://www.coreservlets.com/.
10 (C) 2003 Marty Hall; may be freely used or adapted.
11  -->
12  <HTML><HEAD><TITLE>Employee Insurance Signup</TITLE></HEAD>
13  <BODY BGCOLOR="#FDF5E6">
14  <CENTER>
15  <H1>Employee Insurance Signup</H1>
16
17  <FORM ACTION="/servlet/coreservlets.SubmitInsuranceInfo">
18 Name: <INPUT TYPE="TEXT" NAME="name"><BR>
19 Employee ID: <INPUT TYPE="TEXT" NAME="employeeID"><BR>
20 Number of Children: <INPUT TYPE="TEXT" NAME="numChildren"><BR>
21
22 <INPUT TYPE="CHECKBOX" NAME="married" VALUE="true">Married?<BR>
23 <CENTER><INPUT TYPE="SUBMIT"></CENTER>
24  </FORM>
25
26  </CENTER></BODY></HTML>

bean:

View Code
1 package coreservlets.beans;
2
3  import coreservlets.*;
4
5
6  public class InsuranceInfo {
7 private String name = "No name specified";
8 private String employeeID = "No ID specified";
9 private int numChildren = 0;
10 private boolean isMarried = false;
11
12 public String getName() {
13 return(name);
14 }
15 public void setName(String name) {
16 this.name = ServletUtilities.filter(name);
17 }
18
19
20 public String getEmployeeID() {
21 return(employeeID);
22 }
23 public void setEmployeeID(String employeeID) {
24 this.employeeID = ServletUtilities.filter(employeeID);
25 }
26
27
28 public int getNumChildren() {
29 return(numChildren);
30 }
31 public void setNumChildren(int numChildren) {
32 this.numChildren = numChildren;
33 }
34
35
36 public boolean isMarried() {
37 return(isMarried);
38 }
39
40 public void setMarried(boolean isMarried) {
41 this.isMarried = isMarried;
42 }
43 }

servlet:

View Code
1 package coreservlets;
2
3  import java.io.*;
4  import javax.servlet.*;
5  import javax.servlet.http.*;
6  import coreservlets.beans.*;
7
8
9  public class SubmitInsuranceInfo extends HttpServlet {
10 public void doGet(HttpServletRequest request,
11 HttpServletResponse response)
12 throws ServletException, IOException {
13
14  //一步完成所有参数的填充,info是一个 bean对象
15   InsuranceInfo info = new InsuranceInfo();
16 BeanUtilities.populateBean(info, request);
17
18 response.setContentType("text/html");
19 PrintWriter out = response.getWriter();
20 String docType =
21 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
22 "Transitional//EN\">\n";
23 String title = "Insurance Info for " + info.getName();
24 out.println(docType +
25 "<HTML>\n" +
26 "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" +
27 "<BODY BGCOLOR=\"#FDF5E6\">\n" +
28 "<CENTER>\n" +
29 "<H1>" + title + "</H1>\n" +
30 "<UL>\n" +
31 " <LI>Employee ID: " +
32 info.getEmployeeID() + "\n" +//从bean对象里取值
33   " <LI>Number of children: " +
34 info.getNumChildren() + "\n" +
35 " <LI>Married?: " +
36 info.isMarried() + "\n" +
37 "</UL></CENTER></BODY></HTML>");
38 }
39 }

7,参数缺失或异常时重新显示输入表单

当用户没有填写某些表单时,有时候需要使用默认值(如上述4中讲述),但有时候没有合适的默认值,这时需要

1)用户不应该再次输入已经提供的值

2)缺失的表单域应该突出的表示出来 提醒用户有未填写的项

一种解决方案:

判断bean对象(即表单的form)是否完全为空等情况,根据不同的情况,调用不同的方法去显示---

1 public void doGet(HttpServletRequest request,
2 HttpServletResponse response)
3 throws ServletException, IOException {
4
5 BidInfo bid = new BidInfo();//表单bean对象
6   BeanUtilities.populateBean(bid, request);//通过bean赋值
7
8  //判断bean填充完整性的情形,调用不同的方法去处理
9   if (bid.isComplete()) {
10 showBid(request, response, bid);
11 } else {
12 showEntryForm(request, response, bid);
13 }
14 }

posted @ 2011-04-09 14:45  jinmengzhe  阅读(2021)  评论(0编辑  收藏  举报