文章目录
HttpServletRequest
1 Request概述
我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和代表响应response。
service方法中的request的类型是ServletRequest,而doGet/doPost方法的request的类型是HttpServletRequest,HttpServletRequest是ServletRequest的子接口,功能和方法更加强大。由于HTTP请求消息分为请求行,请求头和请求体三部分。因此,在HttpServletRequest接口中定义了获取请求行,请求头和请求体的相关方法。
2 Requset常用API
2.1 获取请求行信息的相关方法
当访问Servlet时,会在请求消息的请求行中,包含了请求方式,请求资源名,请求路径,HTTP协议信息等信息。
方法声明 | 功能描述 |
String getMethod() | 该方法用于获取HTTP请求消息中的请求方式。 |
String getRequestURI() | 该方法用于获取请求行中资源名称部分,即位于URL的主机和端口之后,参数之前的部分。 |
String getQueryString() | 该方法用于获取请求行中的参数部分,也就是资源路径后面问号以后的所有内容。 |
String getContextPath() | 该方法用于获取WEB工程的名字。 |
String getServletPath() | 该方法用于获取Servlet的名称或Servlet所映射的路径。 |
String getRemoteAddr() | 该方法用于获取请求客户端的IP地址。 |
StringBuffer getRequestURL() | 该方法获取客户端发出请求时的完整URL,包括协议、服务器名、端口号、资源路径等信息,但不包括后面的查询参数部分。 |
@WebServlet(urlPatterns="/get", name="GetRequestServlet")
public class GetRequestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String method = request.getMethod();
System.out.println("method:"+method);
String requestURI = request.getRequestURI();
System.out.println("requestURI:"+requestURI);
StringBuffer requestURL = request.getRequestURL();
System.out.println("requestURL:"+requestURL);
String contextPath = request.getContextPath();
System.out.println("contextPath:"+contextPath);
String remoteAddr = request.getRemoteAddr();
System.out.println("remoteAddr:"+remoteAddr);
String servletPath = request.getServletPath();
System.out.println("servletPath:"+servletPath);
String queryString = request.getQueryString();
System.out.println("queryString:"+queryString);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
}
控制台:
method:GET
requestURI:/demo/get
requestURL:http://localhost:8080/demo/get
contextPath:/demo
remoteAddr:0:0:0:0:0:0:0:1
servletPath:/get
queryString:username=kunkun&username=CTRL
注意:假如是POST提交方式的话,getQueryString的返回值是null
2.2 获取请求头信息的相关方法
方法声明 | 功能描述 |
---|---|
String getHeader(String name) | 获取一个指定头字段的值 |
long getDateHeader(String name) | 获取一个指定头字段的值,并将其值转为int类型 |
int getIntHeader(String name) | 获取一个指定头字段的值,并将其值转为毫秒值 |
Enumeration getHeaderNames() | 获取所有的头字段的名字 |
Enumeration getHeaders(String name) | 获取指定头字段的值(一个头字段可能有多个) |
演示代码:
public class HeaderServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String agent = request.getHeader("User-Agent");
System.out.println("User-Agent头字段的信息:"+agent);
Enumeration<String> headerNames = request.getHeaderNames();
Iterator<String> it = headerNames.asIterator();
while(it.hasNext()) {
System.out.println("头名称:"+it.next());
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
控制台:
User-Agent头字段的信息:
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:46.0) Gecko/20100101 Firefox/46.0
头名称:host
头名称:user-agent
头名称:accept
头名称:accept-language
头名称:accept-encoding
头名称:referer
头名称:connection
注意:referer头字段:浏览器通知服务器,当前请求来自何处。如果是直接访问,则不会有这个头。常用于:防盗链
2.3 获取请求体参数的相关方法
方法声明 | 功能描述 |
---|---|
String getParameter(String name) | 获取指定名称的参数值。 若没有指定名称的参数,返回null。 若包含指定名称参数,但无值,返回空串。 若包含多个指定名称的参数,返回第一个参数值。 |
String[] getParameterValues(String name) | 获取同一个参数名的所有值(如复选框checkbox) |
Map<String,String[]> getParameterMap() | 将请求消息中的所有参数的名称和值装进一个Map对象中返回 |
Enumeration getParameternames() | 返回一个包含请求消息中所有参数名的Enumeration对象 |
演示代码:
public class BodyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//解决输出中文乱码
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//单个获得用户名,密码和爱好
String username = request.getParameter("username");
String password = request.getParameter("password");
String hobby = request.getParameter("hobby");
out.println("用户名:"+username+",密码:"+password+",爱好:"+hobby+"<br/>");
//获得爱好的所有值
String[] hobbys = request.getParameterValues("hobby");
out.print("爱好:");
for(String hobbyOne : hobbys) {
out.print(hobbyOne+" ");
}
out.println("<br/>");
//获得所有的参数名字
Enumeration<String> parameterNames = request.getParameterNames();
out.print("所有参数名:");
while(parameterNames.hasMoreElements()) {
out.print(parameterNames.nextElement()+" ");
}
out.println("<br/>");
//获得参数键值对的Map集合
out.print("所有参数Map集合键值对:"+"<br/>");
Map<String, String[]> map = request.getParameterMap();
for(String key : map.keySet()) {
for(String value : map.get(key)) {
out.println(key+"="+value+"<br/>");
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
浏览器打印内容:
用户名:wangba,密码:666,爱好:tennis
爱好:tennis Pingpong
所有参数名:username password hobby
所有参数Map集合键值对:
username=wangba
password=666
hobby=tennis
hobby=Pingpong
注意:无论是get提交还是post提交上述方法都可以获取到参数名和对应的值。
2.4 获取中文参数乱码问题
用户在页面输入的数据总会有中文,这些中文数据传递到服务端的时候,如果不做处理会出中文乱码的问题。一切出现乱码的问题都是因为字符集不一致引起的,用户在HTML页面输入的中文是由HTML设置的UTF-8码表编码的,而request对象使用的ISO-8859-1编码解码,所以会出现乱码现象。下面分两种情况解决中文乱码问题。
-
post提交方式的解决方法:
request.setcharacterEncoding(“UTF-8”)
,设置request对象的解码方式。- 注意:一定要放在第一次接收参数之前先设置解码的字符集,否则还是会乱码。
-
get提交方式的解决方法:
- tomcat7及以前:
username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
- tomcat8不用处理,因为tomcat8的request缓冲区的默认解码方式就是UTF-8。
- tomcat7及以前:
3 Request的其他功能
3.1 Request是一个域对象
生命周期:
- 创建:在一次请求开始。
- 销毁:一次请求结束。
- 作用范围:一次请求中。
方法声明 | 功能描述 |
---|---|
void setAttribute(String name,Object value) | 将一个键值对存储到ServletRequest对象中 |
Object getAttribute(String name) | 从ServletRequest对象中返回指定名称的属性 |
removeAttribute(String name) | 从ServletRequest对象中删除指定名称的属性 |
注意:关于setAttribute(String name,Object value)方法
- 如果ServletRequest对象中已经存在指定名称的属性,该方法会覆盖原来的属性值。
- 如果传递给该方法的属性值对象为null,则删除指定名称的属性,此时效果等同于removeAttribute方法。
3.2 请求转发
当一个WEB资源收到客户端的请求后,如果希望服务器通知另外一个资源去处理请求,这时除了使用sendRedirect()方法实现请求重定向外,还可以通过RequestDispatcher接口的实例对象来实现。在ServletRequest接口中定义了一个获取RequestDispatcher对象的方法。
①getRequestDispatcher(String path)
:返回封装了某个路径所制定资源的RequestDispatcher对象。需要注意的是,WEB-INF目录中的内容对RequestDispatcher对象也是可见的,因此传递给该方法的资源也可以是WEB-INF目录中的文件。
获得RequestDispatcher对象后,最重要的工作就是通知其他WEB资源处理当前的Servlet请求。
②forward(ServletRequest request,ServletResponse response)
:用于将请求从一个Servlet传递给另外一个WEB资源。
请求转发流程示意图
代码演示:
/*
* 请求转发的Servlet
*/
public class DispacherServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("school", "CTGU");
request.getRequestDispatcher("/result").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package com.itheima.Dispatcher;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ResultServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String shoolName = (String)request.getAttribute("school");
response.getWriter().print("这是请求转发的结果: "+shoolName);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意:
1、在目标资源中调用forward方法时,必须保证此响应没有提交。也就是不要使用 ServletResponse 对象的输出流对象,**因为即便你写入了数据到响应缓冲区,最后也会被清空,**如果缓冲区数据被刷新提交(out.flush),还会抛出IllegalStateException异常。
2、对于forward方法传递的request对象:虽然我们从调用上看,好像是将request对象传递给转动的资源上去了,但是我发现目标资源使用的request对象和转发的资源使用的request对象不是同一个request对象,因为分别从这2个request中获取RequestURL,发现是不一样的。但是在目标资源request提取的Paramter和 Attribute,在转发后的资源的request对象中,依然都可以提取到,且是相同的。所以,二者只是在请求路径相关的属性上不同,其它API调用返回的都是一样的。
3、在forward语句的前后,都不应该有响应输出的语句,应该会被忽略。
4、同时使用请求转发和重定向会报错,Cannot call sendRedirect() after the response has been committed或Cannot forward after response has been committed。
3.3 请求转发和重定向的区别
转发是服务器行为,重定向是客户端行为;
- 重定向的地址栏会发生变化,而转发的地址栏不会发生变化。
- 重定向至少两次请求两次响应,请求转发一次请求一次响应。
- 重定向的路径需要加工程的名字,而请求转发的路径不需要加工程名,但是必须以
“/”
开头。 - 重定向可以跳转到任意网站,而转发只能在服务器内部进行转发。
- 转发2次跳转之间传输的信息不会丢失,重定向2次跳转之间传输的信息会丢失(request域范围)。
- 转发的性能优于重定向,因为转发是服务器内部行为。
- 请求转发可以转发到普通的HTML、WEB-INF下面的资源、其他Servlet资源,而重定向不能重定向到WEB-INF下的资源,其他两个可以。
注意:请求转发是唯一可以访问WEB-INF的资源的方式