探索Android软键盘的疑难杂症
深入探讨Android异步精髓Handler
详解Android主流框架不可或缺的基石
站在源码的肩膀上全解Scroller工作机制
Android多分辨率适配框架(1)— 核心基础
Android多分辨率适配框架(2)— 原理剖析
Android多分辨率适配框架(3)— 使用指南
自定义View系列教程00–推翻自己和过往,重学自定义View
自定义View系列教程01–常用工具介绍
自定义View系列教程02–onMeasure源码详尽分析
自定义View系列教程03–onLayout源码详尽分析
自定义View系列教程04–Draw源码分析及其实践
自定义View系列教程05–示例分析
自定义View系列教程06–详解View的Touch事件处理
自定义View系列教程07–详解ViewGroup分发Touch事件
自定义View系列教程08–滑动冲突的产生及其处理
版权声明
- 本文原创作者:谷哥的小弟
- 作者博客地址:http://blog.csdn.net/lfdfhl
在前几篇博客中我们学习了Tomcat,Http,Servlet,HttpServletResponse在此基础上我们来深入学习Servlet的请求即HttpServletRequest
HttpServletRequest的简单使用
HttpServletRequest代表客户端的请求,当客户端通过HTTP协议访问服务器时与请求相关的所有信息都将被封装在这个对象中,所以我们可通过该对象获得客户端的相关信息。
常用的方法如下:
- getRequestURL():返回客户端发出请求时的完整URL
- getRequestURI():返回请求行中的资源名部分
- getContextPath():返回请求的上下文路径
- getQueryString():返回请求行中的参数部分
- getParameter():返回参数中的具体值
- getRemoteAddr():返回发出请求的客户端的IP地址
- getRemoteHost():返回发出请求的客户端的完整主机名
- getRemotePort():返回客户端所使用的网络端口号
- getMethod():返回客户端使用的请求方式
- getHeaderNames():返回此请求包含的所有头的名称
- getHeader():返回指定的请求头的值
请看如下示例:
/**
* 本文作者:谷哥的小弟
* 博客地址:http://blog.csdn.net/lfdfhl
*/
package cn.com;
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 TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
getRequestInfo(request);
getRequestHeader(request);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
//获取与请求相关的信息
private void getRequestInfo(HttpServletRequest request){
String method=request.getMethod();
StringBuffer requestURL = request.getRequestURL();
String requestURI = request.getRequestURI();
String contextPath = request.getContextPath();
String queryString = request.getQueryString();
String name=request.getParameter("name");
String remoteAddr = request.getRemoteAddr();
String remoteHost = request.getRemoteHost();
int remotePort = request.getRemotePort();
System.out.println("----> method="+method);
System.out.println("----> requestURL="+requestURL);
System.out.println("----> requestURI="+requestURI);
System.out.println("----> contextPath="+contextPath);
System.out.println("----> queryString="+queryString);
System.out.println("----> remoteAddr="+remoteAddr);
System.out.println("----> remoteHost="+remoteHost);
System.out.println("----> remotePort="+remotePort);
}
//获取请求的Header中的信息
private void getRequestHeader(HttpServletRequest request){
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String headKey=headerNames.nextElement();
String headValue=request.getHeader(headKey);
System.out.println(headKey+":"+headValue);
}
}
}
代码写好了,我们现在通过浏览器发出请求:
在Console中观察输入结果:
—-> method=GET
—-> requestURL=http://localhost:8081/TestServlet03/helloServlet
—-> requestURI=/TestServlet03/helloServlet
—-> contextPath=/TestServlet03
—-> queryString=name=lucy
—-> name=lucy
—-> remoteAddr=127.0.0.1
—-> remoteHost=127.0.0.1
—-> remotePort=63484
host:localhost:8081
connection:keep-alive
cache-control:max-age=0
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
upgrade-insecure-requests:1
user-agent:Mozilla/5.0 (Windows NT 10.0;Win64; x64)Chrome/47.0.2526.111
accept-encoding:gzip, deflate, sdch
accept-language:zh-CN,zh;q=0.8
嗯哼,结合这些输出结果再回过头看这些方法就能有更好的体会。在此,再次强调一下:请注意getRequestURL()和getRequestURI()以及getContextPath()、getQueryString()这四个方法的区别
- getRequestURL()返回的是请求的路径,但是不含请求的参数部分
- getRequestURI()返回请求行中的资源名部分,但是不含有请求的主机和端口以及请求的参数部分
- getContextPath()返回请求的上下文,即/+项目名称,比如此处的/TestServlet03
在前几篇博客中我们学习了Tomcat,Http,Servlet,HttpServletResponse在此基础上我们来深入学习Servlet的请求即HttpServletRequest
HttpServletRequest处理表单请求
在刚才的示例中,我们利用getParameter()获取GET请求中请求参数中的具体值,那么在POST请求时又该怎么获取传递给服务端的值呢?请看如下示例
先准备一个表单:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Welcome</title>
</head>
<body>
<form action="/TestServlet03/form" method="post">
用 户:<input type="text" name="username"/>
<br/><br/>
密 码:<input type="password" name="password"/>
<br/><br/>
性 别:<input type="radio" name="gender" value="男" />男
<input type="radio" name="gender" value="女" checked="checked"/>女
<br/><br/>
爱 好:<input type="checkbox" name="hobby" value="摄影"/>摄影
<input type="checkbox" name="hobby" value="唱歌"/>唱歌
<input type="checkbox" name="hobby" value="拍照"/>拍照
<br/><br/>
城 市:
<select name="city">
<option>------请选择------</option>
<option value="dj">东京</option>
<option value="db">大阪</option>
<option value="xt">仙台</option>
</select>
<br/><br/>
<input type="submit" value="欢迎注册VIP会员"/>
</form>
</body>
</html>
再实现服务端的代码:
/**
* 本文作者:谷哥的小弟
* 博客地址:http://blog.csdn.net/lfdfhl
*/
package cn.com;
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 TestForm extends HttpServlet{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
testForm1(request);
}
private void testForm1(HttpServletRequest request)throws ServletException,IOException {
request.setCharacterEncoding("UTF-8");
Enumeration<String> parameterNames = request.getParameterNames();
while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
String[] values = request.getParameterValues(name);
for(int i=0;values!=null&&i<values.length;i++){
System.out.println("name="+name+" "+"value="+values[i]);
}
}
}
}
代码解析如下:
- 利用setCharacterEncoding()设置编码方式
- 利用getParameterNames()获取所有请求参数的名称,请参见代码第28行
对于此处的表单POST提交而言传递的参数的名称分别为username,password,gender,hobby,city - 获取每个参数对于的值,请参见代码第29-35行
嗯哼,现在我们通过浏览器来发起一个请求:
在Console观察打印信息:
name=username value=杉原杏璃
name=password value=123456789
name=gender value=女
name=hobby value=摄影 name=hobby value=拍照
name=city value=dj
在实际开发中,我们可能需要将这些传递给服务端的信息封装成实体,请看如下示例:
先准备一个实体Entity:
/**
* 本文作者:谷哥的小弟
* 博客地址:http://blog.csdn.net/lfdfhl
*/
package cn.com;
import java.io.Serializable;
import java.util.Arrays;
public class User implements Serializable{
private String username;
private String password;
private String gender;
private String[] hobby;
private String city;
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 getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String[] getHobby() {
return hobby;
}
public void setHobby(String[] hobby) {
this.hobby = hobby;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password
+ ", gender=" + gender + ", hobby=" + Arrays.toString(hobby)
+ ", city=" + city + "]";
}
}
请注意,该实体中字段的名字必须与表单中各个name的值相对应
再来看服务端的代码:
private void testForm2(HttpServletRequest request)throws ServletException,IOException {
try {
request.setCharacterEncoding("UTF-8");
User user = new User();
Map<String,String[]> parameterMap = request.getParameterMap();
for (Map.Entry<String, String[]> map : parameterMap.entrySet()) {
String name = map.getKey();
String[] values = map.getValue();
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, User.class);
Method method = propertyDescriptor.getWriteMethod();
if(values.length==1&&!name.equals("hobby")){
method.invoke(user, values[0]);
}else{
method.invoke(user, (Object)values);
}
}
System.out.println("------> "+user);
} catch (Exception e) {
e.printStackTrace();
}
}
代码解析如下:
- 利用getParameterMap()得到请求中所有的参数及其对应的值,请参见代码第5行
注意:有的参数只有一个值,比如该示例中的username;有的参数会有多个值,比如该示例中的hobby - 获取每个参数及其对应的值,请参见代码第7-8行
- 反射出每个参数在实体中的setter()方法,请参见代码第9-10行
- 设置每个参数对应的值,请参见代码第11-15行
请求重定向与请求转发的区别
我们知道:
- 利用response.sendRedirect()实现请求的重定向
- 利用request.getRequestDispatcher().forward()实现请求的转发
请注意它们的区别:
- 重定向时浏览器中的地址栏会发生变化,但是请求转发时浏览器中地址栏不会发生改变。从本质上来讲:重定向是两次不同的请求,而请求转发只向服务端的发送了一次请求由服务端的内部实现请求的跳转。
- 重定向可以跳转到应用的外部,而重定向的范围只能是应用的内部
- 请求转发可利用request.setAttribute()将数据传递到下一个Servlet且下一个Servlet可用request.getAttribute()取出数据;但是重定向不可以也没有道理这么做。至于为什么,请参考第一点。