客户请求的处理:表单数据
常常会看到这样的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 <INPUT TYPE="RADIO" NAME="cardType"
19 VALUE="Visa">Visa<BR>
20
21 <INPUT TYPE="RADIO" NAME="cardType"
22 VALUE="MasterCard">MasterCard<BR>
23 <INPUT TYPE="RADIO" NAME="cardType"
24 VALUE="Amex">American Express<BR>
25 <INPUT TYPE="RADIO" NAME="cardType"
26 VALUE="Discover">Discover<BR>
27 <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字符实体来代换这些符号,---
<--- <
>--- >
"--- "
&--- &
因为这些符号可能被解释为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("<"); break;
61 case '>': filtered.append(">"); break;
62 case '"': filtered.append("""); break;
63 case '&': filtered.append("&"); 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 }
示例:
表单:
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:
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:
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 }