HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。
我们在接收表单提交过来的数据时候,先判断一下它是以什么方式提交的,再以对应方法解决:
javax.servlet.http 包 interface
HttpServletRequest extends ServletRequest
这个接口里面的方法都是以 get 开头的获取请求头信息方法,还有几个以 is 开头的判断方法。
request 常用的方法
- getRequestURL 方法返回客户端发出请求时的完整URL。
- getRequestURI 方法返回请求行中的资源名部分。***
- getQueryString 方法返回请求行中的参数部分。
- getRemoteAddr 方法返回发出请求的客户机的IP地址。***
- getRemoteHost 方法返回发出请求的客户机的完整主机名。
- getRemotePort 方法返回客户机所使用的网络端口号。
- getLocalAddr 方法返回WEB服务器的IP地址。
- getLocalName 方法返回WEB服务器的主机名。
- getMethod 得到客户机请求方式。***
package cn.mengmei.request;
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 RequestDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//在IE地址栏输入:http://localhost:8080/myday06/servlet/RequestDemo1?name=mengmei
//互联网中的统一资源定位符,地址栏?前面的部分
System.out.println(request.getRequestURL()); //http://localhost:8080/myday06/servlet/RequestDemo1
//请求行:GET /myday06/servlet/RequestDemo1?name=mengmei HTTP/1.1
System.out.println(request.getRequestURI()); //请求行中的资源名部分,/myday06/servlet/RequestDemo1
//地址栏?后面的部分
System.out.println(request.getQueryString()); //name=mengmei
//客户端信息
System.out.println(request.getRemoteAddr()); //发出请求的客户机的IP,
System.out.println(request.getRemoteHost()); //发出请求的客户端主机名,
System.out.println(request.getRemotePort()); //发出请求的客户端浏览器占用的网络端口号,56252
System.out.println(request.getMethod()); //得到客户机的请求方式,GET
//服务器信息
System.out.println(request.getLocalAddr()); //WEB服务器的IP地址,
System.out.println(request.getLocalName()); //WEB服务器的主机名,
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Request常用方法---map
- 获得客户机请求头
- getHeader ( String name )
- getHeaders ( String name )
- getHeaderNames ()
package cn.mengmei.request;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String head = request.getHeader("Accept-Encoding");
if(head.contains("gzip")){
//发送压缩数据
}else{
//发送不压缩数据
}
//获取指定名称的所有请求头的值
Enumeration e = request.getHeaders("Accept-Encoding");
while(e.hasMoreElements()){
String value = (String) e.nextElement();
System.out.println(value);
}
System.out.println("------------------------------------------");
//获取所有请求头的名称和值
e = request.getHeaderNames();
while(e.hasMoreElements()){
String name = (String) e.nextElement();
String value = request.getHeader(name);
System.out.println(name + " = " + value);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在IE浏览器地址栏输入:http://localhost:8080/myday06/servlet/RequestDemo2
运行结果如下:
gzip, deflate
------------------------------------------
accept = text/html, application/xhtml+xml, */*
accept-language = zh-CN
user-agent = Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
accept-encoding = gzip, deflate
host = localhost:8080
connection = Keep-Alive
- 获得客户机请求参数(客户端提交的数据)
- getParameter ( String name )
- getParameterValues ( String name )
- getParameterNames ()
- getParameterMap () //框架大量使用 //由于键不能重复,键是String,值是String[]
package cn.mengmei.request;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//http://localhost:8080/myday06/servlet/RequestDemo3?name=mengmei&like=code&like=swim
//获取指定名称参数的第一个值
String name = request.getParameter("name");
System.out.println(name); //mengmei
System.out.println("----------------------------------------");
//获取指定名称参数的所有的值
String[] likes = request.getParameterValues("like");
/*if(likes != null){
for(String like : likes){
System.out.println(like);
}
}*/
for(int i=0; likes!=null && i<likes.length; i++){
System.out.println(likes[i]);
}
System.out.println("----------------------------------------");
//获取所有的请求行参数的名称
Enumeration e = request.getParameterNames();
while(e.hasMoreElements()){
String attr = (String) e.nextElement();
System.out.println(attr);
}
System.out.println("----------------------------------------");
//做框架用的比较多
//获取请求行参数的Map集合
Map<String,String[]> map = request.getParameterMap(); //由于键不能重复,键是String,值是String[]
for(Map.Entry<String, String[]> me : map.entrySet()){
String key = me.getKey();
String[] values = me.getValue();
System.out.println(key + "=" + Arrays.asList(values));
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
浏览器地址栏输入:
http://localhost:8080/myday06/servlet/RequestDemo3?name=mengmei&like=code&like=swim
运行结果如下:
mengmei
----------------------------------------
code
swim
----------------------------------------
name
like
----------------------------------------
name=[mengmei]
like=[code, swim]
Request 通过表单来收集用户数据 以及 常见问题:
- 防盗链
- 各种表单输入项数据的获取
- text、password、radio、checkbox、
- file、select、textarea、hidden
- image、button 给 js 编程用
/myday06/form.html :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>form.html</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<form action="/myday06/servlet/RequestDemo4" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>性别:</td>
<td><input type="radio" name="gender" value="male">男
<input type="radio" name="gender" value="female">女</td>
</tr>
<tr>
<td>所在地:</td>
<td><select name="city">
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="gz">广州</option>
</select></td>
</tr>
<tr>
<td>技术:</td>
<td><input type="checkbox" name="tec" value="html">HTML
<input type="checkbox" name="tec" value="css">CSS
<input type="checkbox" name="tec" value="javascript">javascript
<input type="checkbox" name="tec" value="java">Java </td>
</tr>
<tr>
<td valign="top">留言板:</td>
<td><textarea rows="5" cols="35" name="message" >Leave a message...</textarea></td>
</tr>
<tr>
<td>文件:</td>
<td><input type="file" name="file">
<input type="hidden" name="hidInfo" value="隐藏信息"></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提 交"> <input type="reset" value="重 置"></td>
</tr>
</table>
</form>
</body>
</html>
/myday06/servlet/RequestDemo4 :
package cn.mengmei.request;
import java.io.IOException;
import java.util.Arrays;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestDemo4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String user = request.getParameter("username");
String pass = request.getParameter("password");
String gender = request.getParameter("gender");
String city = request.getParameter("city");
String[] tecs = request.getParameterValues("tec");
String message = request.getParameter("message");
//以后专门有一节讲文件上传怎么处理。
String hidInfo = request.getParameter("hidInfo");
System.out.println(user);
System.out.println(pass);
System.out.println(gender);
System.out.println(city);
if(tecs != null){
System.out.println( Arrays.asList(tecs) );
}
System.out.println(message);
System.out.println(hidInfo);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在浏览器地址栏输入:http://localhost:8080/myday06/form.html
填写表单,并点击提交按钮,服务器端就会接收到用户提交的数据,并打印如下:
mengmei
123456
female
gz
[html, css, javascript, java]
Leave a message...
隐藏信息
如何处理空数据,避免空指针异常:
package cn.mengmei.request;
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 RequestDemo5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username"); //空有 null 、"" 、 " " 这几种情况
if(username==null || username.trim()==""){
//代表用户没带数据过来
}else{
//用户带数据过来了
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
- 请求参数的中文乱码问题
表单是以post方式提交的情况:
package cn.mengmei.request;
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 RequestDemo6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//post方式提交
//服务器端会接收客户端表单提交过来的数据,
//表单是自己写的,用了哪个码表,在这里也将request设置为哪个码表,这样中文数据才可以正确接收。
request.setCharacterEncoding("UTF-8");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
表单是以get方式提交的情况:
package cn.mengmei.request;
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 RequestDemo7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//以get方式提交,设置request的码表是解决不了中文乱码问题的
//因为表单以get方式提交的话,request还是会用ISO-8859-1来解码的。
//request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
//我们只好将接收到的乱码用ISO-8859-1反编译为字节,再用和表单同样的码表将字节转成字符串。
String user = new String(username.getBytes("iso-8859-1"),"UTF-8");
System.out.println(user);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
我们在接收表单提交过来的数据时候,先判断一下它是以什么方式提交的,再以对应方法解决:
package cn.mengmei.request;
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 RequestDemo7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String method = request.getMethod();
if(method.compareToIgnoreCase("get") == 0){
String username = new String(request.getParameter("username").getBytes("iso-8859-1"), "UTF-8");
System.out.println(username);
}else{
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
System.out.println(username);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
改配置文件也可以解决中文乱码问题,在 tomcat\config\server.xml 配置文件中的 <Connector port="8080" /> 标签中添加一条属性
URIEncoding="UTF-8" 即可,但是不建议改。
还有一种方法,将
useBodyEncodingForURI 这个属性置为 "true" 的话,你为 request 设置了什么编码,连接器就默认用什么编码。这种方法更为灵活,但是同样也不建议使用。
- URL地址的编码
如果表单中有超链接带中文参数:
<a href="/myday06/servlet/RequestDemo7?name=中国">点点</a>
这种方式提交数据,你如果还用上面反编码再解码的方式是不行的。
开发里面有一种规范:当 URL 地址后面带了中文的话,一定要经过 URL 编码。
JSP 页面就可以嵌套这样的 java 代码:
String url = URLEncoder.encode("/myday06/servlet/RequestDemo7?name=中国", "UTF-8");
记住:凡是地址栏后面带中文参数一定要经过 URL 编码,编成 ASCII 码后再发送。
request常见应用2:(重点中的重点)
- request对象实现请求转发:请求转发指一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理。
- 请求转发的应用场景:MVC设计模式
- request 对象和 ServletContext 都提供了一个getRequestDispatcher方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。两种没有任何区别,用哪个都可以。
- Request对象同时也是一个域对象,开发人员通过Request对象在实现转发时,把数据通过Request对象带给其他web资源处理。
- setAttribute方法
- getAttribute方法
- removeAttribute方法
- getAttributeNames方法
package cn.mengmei.request;
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 RequestDemo7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "abcdefg"; //产生数据后,用 JSP 排版输出给客户端。
//this.getServletContext().setAttribute("data", data);
//做web工程千万不可以拿Context做容器,
//因为Context代表工程本身,许多人会同时访问这个网站,
//第一个人存进去一个data,第二个人又存进去一个data,
//第二个人就把第一个人的data给覆盖掉了,
//然后第一个人看到的数据可能是第二个人存进去的。
//那么在MVC设计模式下,我们用什么把数据带给JSP呢?
//注意:Request对象自身也是一个容器,每收到一个请求就会创建一个Request对象,
//在请求转发时再将这个Request转发给另一个web资源,
//在一次请求中浏览器地址栏的地址始终不会变,Request对象就始终是那一个。
request.setAttribute("data", data);
//转发方式1:
//this.getServletContext().getRequestDispatcher("/test.jsp").forward(request, response);
//转发方式2:
request.getRequestDispatcher("/test.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
test.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'test.jsp' starting page</title>
</head>
<!-- JSP 底层是一个 Servlet,
请求既然是转发过来的,Request 对象就是转发过来的。
JSP 的几大隐式对象:
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
-->
<body>
<h1>
<%
String data = (String) request.getAttribute("data");
out.write(data);
%>
</h1>
</body>
</html>
浏览器地址栏输入:http://localhost:8080/myday06/servlet/RequestDemo7
显示结果:
abcdefg
请求转发的细节
- forward 方法用于将请求转发到 RequestDispatcher 对象封装的资源。
- 如果在调用 forward 方法之前,在 Servlet 程序中写入的部分内容已经被真正的传送到了客户端,forward 方法将抛出IllegalStateException 异常。
- 如果在调用 forward 方法之前向 Servlet 引擎的缓冲区(response)中写入了内容,只要写入到缓冲区中的内容没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空,但是,已写入到 HttpServletResponse 对象中的响应头字段信息保持有效。
请求重定向和请求转发的区别
一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为
请求转发。
一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源,称之为请求
重定向。
请求重定向和请求转发的区别(细节)
- RequestDispatcher.forward 方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
- 如果传递给 HttpServletResponse.sendRedirect 方法的相对URL以 "/" 开头,它是相对于整个WEB站点的根目录(webapps目录);如果创建 RequestDispatcher 对象时指定的相对URL以 "/" 开头,它是相对于当前WEB应用程序的根目录。
- 通用 HttpServletResponse.sendRedirect 方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发送改变,由初始的URL地址变成重定向的目标URL;调用 RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。
- HttpServletResponse.sendRedirect 方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward 方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。
- RequestDispatcher.forward 方法的调用者与被调用者之间共享相同的 Request 对象和 Response 对象,它们属于同一个访问请求和响应过程;而 HttpServletResponse.sendRedirect 方法调用者与被调用者使用各自的 Request 对象和 Response 对象,它们属于两个独立的访问请求和响应过程。
RequestDispatcher 除了 forward 方法外,还有 include 方法:
- RequestDispatcher.include 方法用于将 RequestDispatcher 对象封装的资源内容作为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能。
- 被包含的 Servlet 程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略。
package cn.mengmei.request;
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 HeadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("这是网头。一般一个网站的网头是保持不变的!");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package cn.mengmei.request;
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 FootServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("这是网脚。一般一个网站的网脚是保持不变的!");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package cn.mengmei.request;
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 RequestDemo8 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
request.getRequestDispatcher("/servlet/HeadServlet").include(request, response);
response.getWriter().write("<br/>这是网页的body!可以DIY哦。<br/>");
request.getRequestDispatcher("/servlet/FootServlet").include(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Request 作业:
- 看Request文档,查看获取请求方式getMethod、请求资源getRequestURI、请求头getHeader、请求参数getParameter的方法。
- 如何向客户机输出不同类型的表单,以收集客户机的数据,并在服务器端获取
- 获取中文数据
- 理解请求转发,以及请求转发方式中,Servlet如何把数据交给jsp显示。
练习: