Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的HttpServletRequest对象(request)对象、和代表响应的HTTPServletResponse对象(response)。

一、Request

HttpServletRequest对象封装了客户端的请求数据,web服务器将之传递给相应servlet处理客户端请求。

Request对象

通过request对象可以获得客户端的信息以及请求参数等等

1、获得客户机请求头

  • getHeader(string name): 获得指定消息头的值(value)
  • getHeaders(String name): 获得指定消息头的值数组(重名的情况)
  • getHeaderNames(): 获得所有的头的名称(key)

2、获得客户机请求参数(客户端提交的数据)

  • getParameter(String name): 获得指定name的请求参数值
  • getParameterValues(String name): 获得指定name请求参数的值数组(重名参数的情况)
  • getParameterNames(): 获得包装所有请求参数的Enumeration对象
  • getParameterMap(): 获得包装所有请求参数的Map<String,String[]>对象,获得该map对象后,可以用内省或者BeanUtils相关方法给相关JavaBean的字段进行赋值。便于数据的传递。
    如有JavaBean User类,用于封装用户数据。
    现有注册页面提交的请求参数,参数名与User的属性名相等。下面是调用BeanUtils对参数的简便封装。
Java Bean - User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package net.yrom.domain;
import java.util.Arrays;
public class User {
private String username;
private String[] password; // 两个密码校验。
private String code;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String[] getPassword() {
return password;
}
public void setPassword(String[] password) {
this.password = password;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return "User [code=" + code + ", password=" + Arrays.toString(password)
+ ", username=" + username + "]";
}
}
Request Demo - RequestDemo1.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package net.yrom.web.servlet;
import net.yrom.domain.User;
import org.apache.commons.beanutils.BeanUtils;
import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 利用Beanutils封装数据
//key:请求参数的名称 String value:请求参数的值 String[]
Map<String,String[]> map = request.getParameterMap();
//把请求数据封转到JavaBean中
User user = new User();
System.out.println("封装前:"+user);
try {
BeanUtils.populate(user, map);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("封装后:"+user);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

3、常用表单数据的获取

1、input:其中radio和checkbox比较特殊。
必须有name属性:如果一个都没有选择,服务器得到的是null
如果选择了任何一个选项,那么将把选中的选项的value值提交给服务器
如果选择了任何一个选项,但该选项没有value属性,则提交的值是on
Tips:
<input type="checkbox" name="married"/>已婚
JavaBean中的boolean married
Beanutils:看到married的值是on或yes,把JavaBean中的married设置为true

2、请求参数的中文乱码问题:一般地,客户端当前使用什么编码就以什么编码提交数据
request.setCharacterEncoding("UTF-8"): 通知servlet使用UTF-8编码。但是只对POST方式有效。
GET方式:因为Tomcat默认是用的ISO-8859-1编码,所以servlet中得到的数据需要再次以ISO-8859-1编码,然后以UTF-8(或者GBK)解码才能正确获得中文信息。
data = new String(data.getBytes("ISO-8859-1"),"UTF-8")

4、ServletRequest域对象

域对象:内部维护了一个Map
void setAttribute(String name,Object obj): 向map中放数据
Object getAttribute(String name): 获取数据
void removeAttribute(String name): 移除数据

二、Response

HttpServletResponse对象代表服务器的响应。这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。

1、response对象

getOutputStream和getWriter方法分别用于得到输出二进制数据、输出文本数据的ServletOuputStream、Printwriter对象。

注意: getOutputStream和getWriter这两个方法互相排斥,只能选择调用其中一个

Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。

2、输出中文数据

2.1 字节流
OuputStream out = response.getOutputStream()
输出的数据的编码可以通过data.getBytes(“编码”)来指定,客户端要想没有乱码,必须知道解码使用的码表。码表不统一必定乱码。

假设要输出的中文数据:"你好".getBytes("UTF-8")
浏览器没有乱码的解决方案:(通知浏览器使用的码表是UTF-8)

  • 设置响应头:response.setHeader("Content-Type","text/html;charset=UTF-8");
  • 设置输出的HTML页面头:out.write("<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'>".getBytes("UTF-8"));
  • 在获取流之前指定输出流所用编码:response.setContentType("text/html;charset=UTF-8");

2.2 字符流getWriter()

1
2
PrintWriter out = response.getWriter();
out.write("中国");//此时查的是ISO-8859-1码表。

解决办法:
更改默认编码ISO-8859-1为你的编码:
1
response.setCharacterEncoding("UTF-8");

假如要用UTF-8输出中文数据
方式一:
1
2
3
4
// 设置获得的输出流使用UTF-8码表
response.setCharacterEncoding("UTF-8");
//通知浏览器使用UTF-8进行解码
response.setHeader("Content-Type","text/html;charset=UTF-8");

方式二:(等同方式一的两个作用)
1
response.setContentType("text/html;charset=UTF-8");

三、Request和Response综合应用

1、请求转发和重定向

1.1、请求转发对象RequestDispatcher
方式一:

1
RequestDispatcher rd = request.getServletContext.getRequestDispatcher("/servlet/RequestDemo2");

地址:必须以”/“开头的绝对路径,代表当前应用。
方式二:
1
RequestDispatcher rd = request.getRequestDispatcher("/servlet/RequestDemo2");

地址:可以使用绝对路径,”/“代表当前应用;允许不以”/“开头,表示使用的是相对路径。
1.2、 请求转发
当需要数据在servlet直接用request域对象来无缝传递,可以用转发实现。
1
2
// 将当前请求转发至/servlet/RequestDemo2
request.getRequestDispatcher("/servlet/RequestDemo2").forward(request, response);

注意:请求转发的时候,web容器会清空response中的数据,转发后当前servlet也无法再向response中写入数据,所以在转发前,源servlet不要刷新或关闭response的流对象

1.3、请求重定向
当请求资源被移动到新地址,可以通过response对象将请求重定向至另一个URL。
方式一:通过设置响应头重定向

1
2
3
4
// 设置响应头为302
response.setStatus(HttpServletResponse.SC_FOUND);
// 将当前请求重定向至"/应用路径/index.html"
response.setHeader("Location", request.getContextPath + "/index.html")

方式二:调用response的sendRedirect方法
1
2
// 将当前请求重定向至"/应用路径/index.html"
response.sendRedirect(request.getContextPath + "/index.html")

1.4、请求重定向和转发的异同
请求重定向:客户端发出了2次请求;地址栏会有相应变化;属于客户端行为,所以无法重定向到访问不到的地址。
请求转发:客户端发出了1次请求;地址栏不会有变化;属于web服务器行为

2、包含

需要将目标组件的输出包含到源组件中,如将所有页面的footer输出信息抽出成为一个单个的servlet或jsp,此时其他servlet或jsp可以将其包含到自己的页面输出中,实现同步footer信息输出。

1
2
// 将Footer中的输出数据包含到当前servlet中
request.getRequestDispatcher("/servlet/FooterServlet").include(request, response);

注意:包含,会把目标组件设置的所有响应头信息清空。