Servlet Request对象

1. request对象和response对象的原理

每向Tomcat发一次请求,Tomcat就会创建一个request和一个response对象,将本次请求的所有数据封装到request对象中,然后将request和response作为实参传递给对应Servlet的service方法,来处理本次请求

2. request对象继承体系结构

1
2
3
4
5
ServletRequest		--	接口
| 继承
HttpServletRequest -- 接口
| 实现
org.apache.catalina.connector.RequestFacade 类(tomcat)

3. 获取请求行

请求行格式如下:

1
GET /webapp/index.html?username=abc HTTP/1.1

3.1. 获取请求方式

getMethod()返回的值只可能是以下几种:

  • "DELETE"
  • "HEAD"
  • "GET"
  • "OPTIONS"
  • "POST"
  • "PUT"
  • "TRACE"
1
2
3
4
String method = req.getMethod();
if (method.equals("GET")) {
System.out.println("...");
}

3.2. 获取虚拟目录

1
String contextPath = req.getContextPath();

3.3. 获取ServletPath

1
String servletPath = req.getServletPath();

3.4. 获取请求URL和URI

例如访问http://localhost:8080/webapp/index.html?username=abc

1
2
3
4
StringBuffer url = req.getRequestURL();  // 获取请求URL   http://localhost:8080/webapp/index.html
String uri = req.getRequestURI(); // 获取请求URI /webapp/index.html
System.out.println("url = " + url.toString());
System.out.println("uri = " + uri);

3.5. 获取URL中的请求参数(GET请求的参数)

1
String queryString = req.getQueryString();

例如访问http://localhost:8080/hello?username=mike&password=123456,得到的queryString是username=mike&password=123456

3.6. 获取请求协议

1
2
String scheme = req.getScheme();  // 获取请求的协议:如http/https/ftp 
String protocol = req.getProtocol(); // 获取请求的协议(含版本号) 如 HTTP/1.1

4. 获取请求头

4.1. 获取Content-Type

1
String contentType = req.getContentType();

4.2. 根据名称获取

String getHeader(String name) 注意如果不存在,则返回null

1
2
// 注意:请求头的name不区分大小写
String userAgent = req.getHeader("User-Agent");

4.3. 遍历请求头

1
2
3
4
5
6
7
8
9
// 获取所有header的名称
Enumeration<String> headers = req.getHeaderNames();
// 遍历所有header
while (headers.hasMoreElements()) {
// 得到该header对应的value
String key = headers.nextElement();
String value = req.getHeader(key);
System.out.println(key + " --- " + value);
}

5. 获取客户端信息

1
2
3
4
String remoteUser = req.getRemoteUser();  // 获取当前缓存的用户,比如Spring Security做权限控制后就会将用户登录名缓存到这里 
String remoteAddr = req.getRemoteAddr(); // 获取客户端IP
String remoteHost = req.getRemoteHost(); // 获取客户端的主机名
int remotePort = req.getRemotePort(); // 获取客户端端口

6. 获取服务器信息

1
2
3
String localAddr = req.getLocalAddr();   // 获取服务器IP
String localName = req.getLocalName(); // 获取服务器主机名
int localPort = req.getLocalPort(); // 获取服务器端口

7. 通用获取请求参数

获取请求参数不区分GET/POST,可以统一用以下几种方式来获取参数的值

7.1. 根据name获取单个值

1
String username = req.getParameter("username");

注意以下几种情况参数的值:

1
2
3
4
http://localhost:8080/hello?aaa=123                  username为null
http://localhost:8080/hello?username&aaa=3 username为空字符串
http://localhost:8080/hello?username=&aaa=3 username为空字符串
http://localhost:8080/hello?username=123&aaa=3 username为"123"

7.2. 根据name获取多个值

有时候同1个name,可能有多个value,例如复选框

1
2
3
<input type="checkbox" name="check" value="1">
<input type="checkbox" name="check" value="2">
<input type="checkbox" name="check" value="3">

勾选之后GET提交的URL如下

1
http://localhost:8080/hello?check=1&check=2&check=3

req.getParameter(name)只能获取第1个value,如果想获取多个,则使用req.getParameterValues(name)

1
2
3
4
String[] checks = req.getParameterValues("check");
for (String value : checks) {
System.out.println(value);
}

要注意,没有对应参数时,req.getParameterValues(name)也是返回null,在用for遍历数组时,会出现空指针异常,所以要先判断是否为null

1
2
3
4
5
6
String[] checks = req.getParameterValues("check");
if (checks != null) {
for (String value : checks) {
System.out.println(value);
}
}

7.3. 遍历所有请求参数

getParameterNames() 获取所有请求参数的名称

1
2
3
4
5
6
Enumeration<String> params  = req.getParameterNames();
while (params.hasMoreElements()) {
String name = params.nextElement();
String value = req.getParameter(name);
System.out.println(name + " === " + value);
}

getParameterMap() 获取所有请求参数以及值。key是参数名,value是参数的值,因为值可能有多个,所以是数组类型

1
2
3
4
Map<String, String[]> map = req.getParameterMap();
map.forEach((name, values) -> {
System.out.println(name + " === " + Arrays.toString(values));
});

8. 获取请求体

只有POST请求,才有请求体。Request将请求体封装成流,想获取请求体,你首先要获取流对象,再从流对象中取数据。

你可以从Request对象获取两种流,如果数据是字符,就用字符流,如果是字节,就用字节流

  • BufferedReader getReader() 获取字符流
  • ServletInputStream getInputStream() 获取字符流

读取完之后,流不必close(),因为流是从request中获取的,本次请求结束后,request对象会自动被销毁

读取字符示例

1
2
3
4
5
6
BufferedReader br = req.getReader();
String line = null;
while ((line = br.readLine()) != null) {
line = br.readLine();
System.out.println(line);
}

9. 请求转发

请求转发:一种在服务器内部的资源跳转方式

转发步骤:

  1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
  2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@WebServlet("/hello")
public class MyServlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("hello");
req.getRequestDispatcher("/world").forward(req, resp); // 转发请求
}
}

@WebServlet("/world")
public class MyServlet2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("world");
}
}

转发特点:

  1. 浏览器地址栏路径不发生变化
  2. 只能转发到当前服务器内部资源中。
  3. 转发是一次请求

10. 共享数据

共享数据:

  • 域对象:一个有作用范围的对象,可以在范围内共享数据
  • request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据

方法:

  • void setAttribute(String name,Object obj) 存储数据
  • Object getAttitude(String name) 通过键获取值
  • void removeAttribute(String name) 通过键移除键值对
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@WebServlet("/hello")
public class MyServlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("hello");
req.setAttribute("age", 100); // 转发前存储数据
req.getRequestDispatcher("/world").forward(req, resp); // 转发请求
}
}

@WebServlet("/world")
public class MyServlet2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int age = (int) req.getAttribute("age");
System.out.println("age = " + age); // 获取数据
System.out.println("world");
}
}
panchaoxin wechat
关注我的公众号
支持一下