客户请求的处理:表单数据
1、表单数据作用
http://host/path?user=Marty+Hall&origin=bwi
问好后面的部分被称为表单数据(form data)或查询数据(query data).
表单数据可以跟在问好后面附加到URL的结尾,GET请求即采用这种方式;
表单数据还可以在单独的行中发送到服务器,POST请求即为如此。
1、使用FORM元素创建HTML表单:
<FORM ACTION="...">...</FORM>
如果省略ACTION,那么数据将提交给当前页面对应的URL
2、使用输入元素手机用户数据
3、接近表单的尾部放置提交按钮
从表单数据中提取数据,一般是服务器端编程中最冗长乏味的工作之一
1、在使用servlet技术之前,一般必须采用一种方式读取GET请求的数据(传统CGI(Common Gateway Interface)中一般采用QUERY_STRING环境变量),另一种不同的方式读取POST请求的数据(传统CGI中,通过读取标准输入)
2、将&两边对切,键值对=分离
4、必须对值进行URL解码:解开浏览器对某些字符的编码。在发送字母数字字符时,浏览器不做任何改动,但会将空格转换成加号,其他字符转换成%XX,XX是该字符的ASCII码值,以16进制表示
5、参数的值右可能忽略或者出现多次,需要特殊处理
2、servlet中读取表单数据
servlet自动完成了前面提取表单数据的操作。
request.getParameter可以得到表单参数的值。如果参数多次出现,还可以调用request.getParameterValues;如果希望得到当前请求中所有参数的完整列表,可以调用request.getParameterNames。极少情况下,可能需要读取原始的请求数据自己对它进行分析,这时候可以调用getReader或者getInputStream。
单个值的读取:
HttpServletRequest的getParameter方法,提供大小写敏感的参数名作为方法的参数。不管是GET请求还是POST请求,servlet知道客户使用的是哪种请求方法,并使用恰当的方法请求数据
多个值的读取:
一组参数名可能在表单数据中多次出现,则调用getParameterValues,返回元素数组。
参数名的查找:
getParameterNames和getParameterMap
getParameterNames以Enumeration的形式返回这种列表。如果请求中没有参数,返回空的Enumeration不是null。Enumeration只是一个接口,保证实现类实现了hasMoreElements和nextElement方法,并不保证具体的实现会采用某种特定的数据结构,所以不要指望getParameterNames返回的参数会遵照在HTML表单中的次序。
getParameterNames的替代方案是getParameterMap。这个方法返回一个Map:参数名是表的键,参数值是表的值
原始表单数据的读取以及对上载文件的分析:getReader或getInputStream
除了读取个别的表单参数之外,我们还可以调用HttpServletRequest提供的getReader或getInputStream直接访问查询数据,之后使用获取的流,分析原始的输入。但要注意,如果这种方式,不能保证可以同时使用getParameter。
对于常规参数,读取原始数据不是一个好主意,因为这些输入既没有经过分析,也没有经过URL解码。但是两种情况下需要读取原始的输入:
1、数据不是由HTML表单提交,而是来自于定制的客户端程序
2、数据来自上载的文件时,可能需要自己读取数据。HTML支持一种FORM元素(<input type="file">),它允许客户将文件上载到服务器。遗憾的是,servlet的API没有定义任何机制来读取这类文件,因此需要借助第三方库。最广泛的是http://jakarta.apache.org/commons/fileupload/
多字符集输入的读取:setCharacterEncoding
默认情况下,request.getParameter使用服务器的当前字符集进行解释输入。要改变这种默认行为,需要使用SerbletRequest的setCharacterEncoding方法。但是,如果输入中使用了多种字符集,应该怎么办呢?这种情况下,不能简单地使用普通的字符集名调用serCharacterEncoding。之所以有这种限制,是因为setCharacterEncoding必须在访问任何请求参数之前调用,同时,多数情况下我们需要使用请求中的参数来确定字符集。
因此我们只有两种选择:按照某个字符集读取参数,然后将它转换到另外的字符集;或者使用某些字符集提供的自动检测特性。
第一种选择,首先提取感兴趣的参数,使用getBytes提取出原始的字节数据,之后将这些字节连同期望字符集的名称一同传递给String的构造参数。例子:
String firstNameWrongEncoding = request.getParameter("firstName");
String firstName = new String(firstNameWrongEncoding.getVytes(), "Shift_JIS");
第二种选择,需要使用一种支持默认字符集进行检测和转换的字符集。java所支持的字符集的完整列表在http://java.sun.com/j2se/1.4.1/docs/guide/intl/encoding.doc.html获得。例如如果允许输入既可以是英语,也可以是日语,则要使用下面的语句:
request.setCharacterEncoding("JISAutoDetect");
String firstName = request.getParameter("firstName");
form的action最好写相对路径,为了方便移植。
参数缺失或异常时默认值的应用:
用户没有提供必需额信息,servlet如何处理?两种答案;使用么,默认值或重新显示这个表单(提示用户缺失的值)
分析请求的参数,需要检查下面三种情况:
1、参数的值为null
2、参数的值为空字符串
最好使用trim移除用户可能输入的任何空格,因为大多数情况下,一般会将纯空格当成缺失数据
3、参数的值为非空字符串,但格式错误
过滤字符串中的HTML特殊字符:
一般的,如果servlet希望生成含有诸如<或>等字符的HTML,只需要简单地使用标准的HTML字符实体--<或>;。类似的,如果servlet要在HTML属性值。
手动转换有点恶心。出现在两种情况:1、字符串来自程序摘录;2、字符串来自表单数据
执行过滤的代码:
替换字符串中的<,>,",和&比较简单,多种不同方式都能完成。但需要牢记Java的字符串是不可修改的,因此重复的字符串凭借需要复制许多字符串片段,并且在使用后废弃。
String s1 = "hello";
String s2 = s1 + " World";
由于s1是不可修改的,第二行代码首先要生成s1的副本,将“world”追加到该副本,然后这个副本就被废弃。为了避免生成和复制这些临时对象所带来的开销,在循环中执行重复性拼接操作时,应该使用可以改变的数据结构:StringBuffer是通常的选择。
根据请求参数自动填充Java对象:表单bean
jsp可以使用标签达到将表单信息自动注入bean的做法。jsp是特殊的servlet,但是很遗憾,servlet没有类似的方法。我们使用apache-beanutils完成这个转换。
数据回显
1、 同一servlet提供表单、处理数据并提供最后的结果
2、jsp提供表单,servle处理数据并返回结果。