JavaWeb-Http通信
序言
HttpServletRequest和HttpServletResponse是在Servlet中常见的请求和响应方式,这是web交互最基本的模式。
客户端每次请求,都会创建request对象和response对象 —— 被传递到 service、doGet、doPost 中。
HttpServletRequest 封装 客户端相关信息,服务器Servlet程序可以通过request对象 操作客户端信息。
HttpServletResponse 封装服务器 向客户端发送响应数据信息,Servlet程序通过response对象 向客户端发送响应。
1、HttpServletRequest
request对象是请求对象,在客户端向服务器请求一次就创建一个request对象,并且存储了请求的信息。所以在表单进行提交时,我们可以通过request对象获取用户提交的信息。
(1) 常用的API
方 法 说 明
getAttributeNames() 返回当前请求的所有属性的名字集合
getAttribute(String name) 返回name指定的属性值
getCookies() 返回客户端发送的Cookie
getsession() 返回和客户端相关的session,如果没有给客户端分配session 则返回null
getsession(boolean create) 返回和客户端相关的session,如果没有给客户端分配session, 则创建一个session并返回
getParameter(String name) 获取请求中的参数,该参数是由name指定的
getParameterValues(String name) 返回请求中的参数值,该参数值是由name指定的
getCharacterEncoding() 返回请求的字符编码方式
getContentLength() 返回请求体的有效长度
getInputStream() 获取请求的输入流中的数据
getMethod() 获取发送请求的方式,如get、post
getParameterNames() 获取请求中所有参数的名字
getProtocol() 获取请求所使用的协议名称
getReader() 获取请求体的数据流
getRemoteAddr() 获取客户端的IP地址
getRemoteHost() 获取客户端的名字
getServerName() 返回接受请求的服务器的名字
getServerPath() 获取请求的文件的路径
综合实例:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 通过request api 获得客户机信息
*/
public class RequestServlet1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 问题一 区分 getRequestURL 和 getRequestURI
System.out.println("url:" + request.getRequestURL()); // 返回 http://192.168.1.114/day06/request1
System.out.println("uri:" + request.getRequestURI()); // 返回 /day06/request1
// 问题二:了解 通过 getQueryString 可以获得 get方式提交查询串 url中?后面部分
System.out.println("querystring:" + request.getQueryString());
// 获得客户端ip
System.out.println("ip: " + request.getRemoteAddr());// 192.168.1.103
// 通过 getContextPath 获得工程虚拟目录名称
System.out.println(request.getContextPath()); // 返回 /day06
// 通过getMethod 获得请求方式
System.out.println("请求方式 : " + request.getMethod());// GET
// 问题: 获得当前访问资源路径 --- /request1
System.out.println("当前访问资源路径 :"
+ request.getRequestURI().substring(
request.getContextPath().length()));//--/request1
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
(2) 从Request获得请求参数
什么是请求参数? 用户通过请求向服务器提交一些数据:
<a href="url?xxx=xxx" >、<form method="get"> 、 <form method="post">
例如:
第1种、Get方式提交数据:其中包含使用超链接(提交数据以“?”方式)、sendRedirect()两种:
/day06/request4?name=zhangsan&city=beijing //包括两个参数的 name 和 city
第2种、通过form(表格)的Post方式提交数据(提交数据能用post就用post)。
获得request请求参数,常用API四个:
getParameter --- String 通过name获取值,如果是多值只取第一个
getParameterValues --- String[] 通过name获得多值 checkbox
getParameterNames --- Enumeration<String> 获得所有name
getParameterMap --- Map<String,String[]> key:name value:多值
综合实例(含两种提交参数的方式):
<!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>Insert title here</title>
</head>
<body>
<h1>分别以get 和 post方式 提交数据</h1>
<h1>第一种 通过超链接 提交数据 以?方式</h1>
<a href="/day06/request4?name=zhangsan&city=beijing">超链接提交数据</a>
<h1>第二种 通过form的post方式提交数据</h1>
<form action="/day06/request4" method="post">
请输入姓名 <input type="text" name="name" /><br/>
请输入城市 <input type="text" name="city" /> <br/>
<input type="submit" value="提交" />
</form>
</body>
</html>
服务器获取客户端提交的参数:
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 RequestServlet4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 通过getParameter 获得请求数据
String name = request.getParameter("name");
System.out.println(name);
String city = request.getParameter("city");
System.out.println(city);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
A、详解get方式提交数据
常见的get方式提交数据有两种:使用超链接,sendRedirect()。
1、重定向——sendRedirect():
sendRedirect("servlet的地址?参数名="+参数值 &"参数名="+参数值);
2、使用超链接:
<a href="/zhongfucheng/Servlet111?username=xxx">使用超链接将数据带给浏览器</a>
我们来使用一下,通过超链接将数据带给浏览器:
<a href="/zhongfucheng/Servlet111?username=xxx">使用超链接将数据带给浏览器</a>
在Servlet111接收数据:
//接收以username为参数名带过来的值
String username = request.getParameter("username");
System.out.println(username);
注意看浏览器左下角:
服务器成功接收到浏览器发送过来的数据:
并且,传输数据明文的出现在浏览器的地址栏上:
sendRedirect()和超链接类似,在这里就不赘述了。
B、详解使用Post提交数据
案例1:
下面咱们来编写一个最复杂表单,及其数据的获取:
代码:
<!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>Insert title here</title>
</head>
<body>
<!-- 最复杂form表单 -->
<!-- 用户注册 -->
<form action="/day06/request5" method="get">
<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>
<input type="checkbox" name="hobby" value="sport"/>运动
<input type="checkbox" name="hobby" value="drink"/>颤酒
<input type="checkbox" name="hobby" value="music"/>音乐
</td>
</tr>
<!-- 下拉框 -->
<tr>
<td>城市</td>
<td>
<select name="city">
<option value="hefei">合肥</option>
<option value="nanjing">南京</option>
<option value="shanghai">上海</option>
<option value="shouxian">寿县</option>
</select>
</td>
</tr>
<!-- 多行文本框 -->
<tr>
<td>个人简介</td>
<td><textarea rows="5" cols="60" name="introduce"></textarea></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="注册"/></td>
</tr>
</table>
</form>
</body>
</html>
获取参数:
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;
/**
* 获得最复杂form 的所有数据
*/
public class RequestServlet5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 解决post乱码
//request.setCharacterEncoding("utf-8");//只能对请求体重新编码
// 通过 getParameter 获得指定数据
String username = request.getParameter("username");
System.out.println(username);// 获得一个值
// 解决get乱码 --- 使用手动编码
// username = URLEncoder.encode(username, "ISO-8859-1");// 用ISO编码
// username = URLDecoder.decode(username, "utf-8"); // 用utf-8解码
username = new String(username.getBytes("ISO-8859-1"), "utf-8");
System.out.println(username);
// 非空校验
if(username !=null && username.trim().length()>0){
System.out.println("username 合法");
}
// 使用 getParameter 获得 checkbox 提交数据。默认只能获得第一个数据
String hobby = request.getParameter("hobby"); // 多选框
System.out.println(hobby);
// 获得checkbox所有提交数据--- getParameterValues
String[] hobbies = request.getParameterValues("hobby");
System.out.println(Arrays.toString(hobbies));
System.out.println("--------------------------");
// 打印所有请求提交参数
// 方式一 : 先获得所有参数 name ,然后通过name 获得value
Enumeration<String> names = request.getParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
System.out.println(name +":"+ Arrays.toString(request.getParameterValues(username)));
}
System.out.println("--------------------------");
// 方式二 :通过request.getParameterMap
Map<String,String[]> parameterMap = request.getParameterMap();
Set<String> keys = parameterMap.keySet();
for (String key : keys) {// key是参数 name
System.out.println(key +":"+ Arrays.toString(parameterMap.get(key)));
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
案例2:
<form action="/zhongfucheng/Servlet111" 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="男">男
<input type="radio" name="gender" value="女">女
</td>
</tr>
<tr>
<td>爱好</td>
<td>
<input type="checkbox" name="hobbies" value="游泳">游泳
<input type="checkbox" name="hobbies" value="跑步">跑步
<input type="checkbox" name="hobbies" value="飞翔">飞翔
</td>
</tr>
<input type="hidden" name="aaa" value="my name is zhongfucheng">
<tr>
<td>你的来自于哪里</td>
<td>
<select name="address">
<option value="广州">广州</option>
<option value="深圳">深圳</option>
<option value="北京">北京</option>
</select>
</td>
</tr>
<tr>
<td>详细说明:</td>
<td>
<textarea cols="30" rows="2" name="textarea"></textarea>
</td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
<td><input type="reset" value="重置"></td>
</tr>
</table>
在Servlet111中获取到提交的数据,代码如下:
//设置request字符编码的格式
request.setCharacterEncoding("UTF-8");
//通过html的name属性,获取到值
String username = request.getParameter("username");
String password = request.getParameter("password");
String gender = request.getParameter("gender");
//复选框和下拉框有多个值,获取到多个值
String[] hobbies = request.getParameterValues("hobbies");
String[] address = request.getParameterValues("address");
//获取到文本域的值
String description = request.getParameter("textarea");
//得到隐藏域的值
String hiddenValue = request.getParameter("aaa");
....各种System.out.println().......
向表单输入数据:
Servlet111得到表单带过来的数据,最后的一个数据是隐藏域带过来的:
(3) 解决中文乱码问题
细心的朋友会发现,我在获取表单数据的时候,有这句代码request.setCharacterEncoding(“UTF-8”);,如果没有这句代码,会发生什么事呢?我们看看。
再重新填写数据:
在服务器查看提交过来的数据,所有的中文数据都乱码了:
来这里我们来分析一下乱码的原因,在前面的博客中我已经介绍了,Tomcat服务器默认编码是ISO 8859-1,而浏览器使用的是UTF-8编码。浏览器的中文数据提交给服务器,Tomcat以ISO 8859-1编码对中文编码,当我在Servlet读取数据的时候,拿到的当然是乱码。而我设置request的编码为UTF-8,乱码就解决了。
接下来使用get方式传递中文数据,把表单的方式改成get即可当我们访问的时候。又出现乱码了!
于是我按照上面的方式,把request对象设置编码为UTF-8试试:
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
结果还是乱码。这是为什么呢?我明明已经把编码设置成UTF-8了,按照post方式,乱码问题已经解决了!。我们来看看get和post方式的区别在哪?为什么post方式设置了request编码就可以解决乱码问题,而get方式不能呢。
首先我们来看一下post方法是怎么进行参数传递的。当我们点击提交按钮的时候,数据封装进了Form Data中,http中多了一个上传请求头,既然request对象封装了http请求,所以request对象可以解析到发送过来的数据,于是只要把编码设置成UTF-8就可以解决乱码问题了。
而get方式不同,它的数据是从消息行带过去的,没有封装到request对象里面,所以使用request设置编码是无效的。
要解决get方式乱码问题也不难,我们既然知道Tomcat默认的编码是ISO 8859-1,那么get方式由消息体带过去给浏览器的时候肯定是用ISO 8859-1编码了。
/此时得到的数据已经是被ISO 8859-1编码后的字符串了,这个是乱码
String name = request.getParameter("username");
//乱码通过反向查ISO 8859-1得到原始的数据
byte[] bytes = name.getBytes("ISO8859-1");
//通过原始的数据,设置正确的码表,构建字符串
String value = new String(bytes, "UTF-8");
上面的代码有些难理解,我画张图说明一下:
经过我们手工转换,再来访问一下:
总结:
1、post方式直接改request对象的编码;
2、get方式需要手工转换编码;
3、提交数据能用post就用post。
(4) 转发request中的数据
Request对象同时是一个域对象,开发人员通过request对象在实现转发时,把数据通过request对象带给其他web资源处理。
|--setAttribute方法
|--getAttribute方法
|--removeAttribute方法
|--getAttributeNames方法
request方法提供了一个getRequestDispatcher方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发,从而共享请求中的数据。
使用request实现Servlet之间的通讯的简单代码:
//以username为关键字存ShenBinwei值
request.setAttribute("username", "ShenBinwei");
//获取到requestDispatcher对象
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/Servlet222");
//调用requestDispatcher对象的forward()实现转发,传入request和response方法
requestDispatcher.forward(request, response);
HttpServletRequest 和 ServletContext 类似 都是数据域对象 , 以Map方式保持数据,二者的主要区别在于存活时间不同:
ServletContext对象 服务器启动对象创建,服务器停止对象销毁
ServletRequest对象 当产生一次请求时 创建,当响应结束后,对象销毁
一般的原则:可以使用request就尽可能使用request。因为ServletContext代表着整个web应用,使用ServletContext会消耗大量的资源,而request对象会随着请求的结束而结束,资源会被回收。使用request域进行Servlet之间的通讯在开发中是非常频繁的。
Request数据域对象传递数据原理:
代码示例:
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 通过AServlet传递一个数据 给 BServlet
*/
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//在使用forward之前 不能将响应内容传输到客户端
// 情况一 如果flush ,不能forward
// response.getWriter().println("Hello");// Hello默认输出浏览器,服务器内部缓存
// response.getWriter().flush();
// 情况二 在同一个Servlet不能使用多次 forward 或者 sendRedirect
// response.sendRedirect("/day06/welcome.html");
response.getWriter().println("Hello"); // Hello输出到内存缓冲区。在forward时,缓冲区会被清除
// 通过request对象传递
// 向request域对象 保存一个属性
request.setAttribute("name", "itcast");
// 传递数据给 BServlet 必须使用请求转发
RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
dispatcher.forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
获取传递的Request的参数:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 接收A转发 request对象
*/
public class BServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 因为是同一个Request对象
System.out.println(request.getAttribute("name"));
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
【转发 和 重定向 的区别】:
Response的sendRedirect()可以实现重定向,做到的功能是页面跳转,使用request的getRequestDispatcher.forward(request,response)实现转发,做到的功能也是页面跳转,他们有什么区别呢?
(5) RequestDispatcher的include()方法
RequestDispatcher对象调用forward()可以实现转发上面已经说过了。RequestDispatcher还有另外一个方法include(),该方法可以实现包含,有什么用呢?
我们在写网页的时候,一般网页的头部和尾部是不需要改变的。如果我们多个地方使用Servlet输出网头和网尾的话,需要把代码重新写一遍。而使用RequestDispatcher的include()方法就可以实现包含网头和网尾的效果了。
我们来操作吧!现在我有网头和网尾的Servlet:
使用Servlet111将网头和网尾包含:
request.getRequestDispatcher("/Head").include(request, response);
response.getWriter().write("--------------------------------------------");
request.getRequestDispatcher("/Foot").include(request, response);
访问一下Servlet111,成功把网头和网尾包含了:
(6) HttpServletRequest应用-防盗链
什么是防盗链呢?
比如:我现在有海贼王最新的资源,想要看海贼王的要在我的网页上看。现在别的网站的人看到我有海贼王的资源,想要把我的资源粘贴在他自己的网站上。这样我独家的资源就被一个CTRL+C和CTRL+V抢走了?而反盗链就是不能被他们CRTL+C和CRTL+V。
下面我模拟一下场景。
1、现在我首页先有一个超链接,指向着海贼王最新资源:
2、当我点进去,就能看到海贼王最新资源了:
3、其他的人可以通过复制粘贴我的地址,放到它们的网页上:
4、这样我就划不来啦【我的广告你来没看呢!】。想要看我的资源,就必须经过我的首页点进去看。
想要实现这样的效果,就要 获取Referer这个消息头,判断Referer是不是从我的首页来的。如果不是从我的首页来的,跳转回我的首页。
//获取到网页是从哪里来的
String referer = request.getHeader("Referer");
//如果不是从我的首页来或者从地址栏直接访问的,
if ( referer == null || !referer.contains("localhost:8080/zhongfucheng/index.jsp") ) {
//回到首页去
response.sendRedirect("/zhongfucheng/index.jsp");
return;
}
//能执行下面的语句,说明是从我的首页点击进来的,那没问题,照常显示
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("路飞做了XXXXxxxxxxxxxxxxxxxx");
5、首先按正常预想的,别人从首页点击我的资源,访问我海贼王最新的资源:
能够成功访问到资源:
6、如果我在浏览器直接输入地址【此时Referer是为null的】,我们来看看:
结果是跳回到首页上,不能顺利直接访问到海贼王资源:
7、再试试,如果别人粘贴了我的资源url,在它的网页上挂了一个网址呢:
在别人网页上点击的时候:
又跳回到了我的首页了:
哈哈哈!!你必须老老实实访问我的主页(看完广告)才能访问到我的资源!防盗链实施成功!
2、HttpServletResponse
在Servlet中,当用户发出请求后,接下来就是需要响应,而响应用另一个对象Response对象。这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。
HttpServletResponse继承了ServletResponse接口,并提供了与Http协议有关的方法,这些方法的主要功能是设置HTTP状态码和管理Cookie。HttpServletResponse对象代表服务器的响应。
HttpServletResponse对象可以向客户端发送三种类型的数据:
a.响应头(Response headers)
b.状态码(Protocol—Status code—Description)
c.实体数据(Entity body )
(1) Http响应的格式
A、来个实例:
响应(服务器—>浏览器)
HTTP/1.1 200 OK --响应行
Server: Apache-Coyote/1.1 --响应头(key-value)
Content-Type: text/html;charset=utf-8
Content-Length: 17
Date: Wed, 16 Nov 2016 07:16:46 GMT
--一个空行
this is a Servlet --实体内容
B、响应行:
1)http协议版本:同请求行
2)状态码: 服务器处理请求的结果(状态)
常见的状态码:200 302 304 404 500
a)200: 请求处理成功
b)302: 客户端重定向
c)304: 客户端访问资源没有被修改,客户端访问本地缓存
d)404: 访问资源不存在
e)500: 服务器内部出错
C、常见响应头:
Location: http://www.it315.org/index.jsp --表示重定向的地址,该头和302的状态码一起使用。
Server:apache tomcat --表示服务器的类型
Content-Encoding: gzip --表示服务器发送给浏览器的数据压缩类型
Content-Length: 80 --表示服务器发送给浏览器的数据长度
Content-Language: zh-cn --表示服务器支持的语言
Content-Type: text/html; charset=GB2312 --表示服务器发送给浏览器的数据类型及内容编码
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT --表示服务器资源的最后修改时间
Refresh: 1;url=http://www.it315.org --表示定时刷新
Content-Disposition: attachment; filename=aaa.zip --表示告诉浏览器以下载方式打开资源(下载文件时用到)
Transfer-Encoding: chunked
Set-Cookie:SS=Q0=5Lb_nQ; path=/search --表示服务器发送给浏览器的cookie信息(会话管理用到)
Expires: -1 --表示通知浏览器不进行缓存
Cache-Control: no-cache
Pragma: no-cache
Connection: close/Keep-Alive --表示服务器和浏览器的连接状态。close:关闭连接 keep-alive:保存连接
(2) 常用的API
方 法 说 明
addCookie(Cookie cookie) 将指定的Cookie加入到当前的响应中
addHeader(String name,String value) 将指定的名字和值加入到响应的头信息中
containsHeader(String name) 返回一个布尔值,判断响应的头部是否被设置
encodeURL(String url) 编码指定的URL
sendError(int sc) 使用指定状态码发送一个错误到客户端
sendRedirect(String location) 发送一个临时的响应到客户端
setDateHeader(String name,long date) 将给出的名字和日期设置响应的头部
setHeader(String name,String value) 将给出的名字和值设置响应的头部
setStatus(int sc) 给当前响应设置状态码
setContentType(String ContentType) 设置响应的MIME类型
(3) 设置状态码
A、response.setStatus() 设置状态码
B、response.sendError() 设置状态码,调用默认对应页面
(4) 设置响应头
response.setHeader(“name”,”value”) 设置响应头。
(5) 设置实体内容
A、response.getWriter().writer(); 发送字符(中文)实体内容。
B、response.getOutputStream().writer() 发送字节实体内容 。
(6) Response完成请求重定向
请求重定向指:一个web资源收到客户端请求后,通知客户端去访问另外一个web资源,这称之为请求重定向。
案例一:
通过302 + Location 头信息实现页面重定向效果
response.setStatus(302);
response.setHeader("Location", "/day06/welcome.html");
完整代码:
package ustc.lichunchun.servlet.response.demo1;
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 ResponseServlet1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("response1 ...");
//response.setStatus(500);//通过setStatus 向客户端设置不同响应 状态码
// 302 客户端重定向 --- 结合 Location头信息一起使用
response.setStatus(302);
// 通知浏览器 定向到哪个页面
response.setHeader("Location", "/day06/welcome.html");// 相对路径 和 绝对路径
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
(7) Response登陆重定向功能
在Response API 中提供 response.sendRedirect—- 完成302+Location重定向效果.例如: response.sendRedirect(“/day06/welcome.html”);
案例二:
登陆重定向:用户登录时,用户名密码错误,重定向回登陆页面
代码:
<!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>Insert title here</title>
</head>
<body>
<form action="/day06/response2" method="post">
用户名 <input type="text" name="username" /><br/>
密码 <input type="password" name="password"/><br/>
<input type="submit" value="登陆"/>
</form>
</body>
</html>
package ustc.lichunchun.servlet.response.demo2;
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 ResponseServlet2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 获得客户端提交用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2、判断是否正确 ,假设 admin / admin
if("admin".equals(username) && "admin".equals(password)){
// 用户名 和 密码正确
// response.setStatus(302);
// response.setHeader("Location", "/day06/welcome.html");
// 使用response.sendRedirect完成重定向
response.sendRedirect("/day06/welcome.html");
}else{
// 不正确
// response.setStatus(302);
// response.setHeader("Location",
// "/day06/response/demo2/login.html");
//第一个/day06代表绝对路径工程名,第二个/代表WebRoot
response.sendRedirect("/day06/response/demo2/login.html");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
结果:
对比:
(8) Response自动刷新
案例三:自动刷新网页
- 登陆成功,5秒后自动跳转XX页面
原理:通过refresh 头信息
格式:refresh:时间;url=跳转路径(绝对路径)
例如: refresh:3;url=http://www.itcast.cn ——– 3秒后自动跳转http://www.itcast.cn网站
代码:
<!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>Insert title here</title>
</head>
<body>
<h1>自动刷新 跳转后页面!!!</h1>
</body>
</html>
package ustc.lichunchun.servlet.response.demo3;
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 ResponseServlet3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 通过refresh 头信息完成跳转
response.setHeader("refresh", "3;url=/day06/response/demo3/result.html");
response.setContentType("text/html;charset=utf-8");// 设置响应编码
response.getWriter().println("3秒后 将跳转 result.html页面!");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
结果:
跳转以后:
* HTML 页面中存在一类非常特殊标签 , 起到设置头信息作用,和http头信息相同效果。http-equiv相当于头信息 name、content相当于头信息 value
<meta content="3;url=/day06/response/demo3/result.html" http-equiv="refresh"> ---- 完成自动跳转
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<!-- meta标签非常特殊, 实现http头信息相同效果 -->
<!-- http-equiv 相当于 头信息 name -->
<!-- content 相当于头信息value -->
<meta http-equiv="refresh" content="3;url=/day06/response/demo3/result.html">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>通过 meta实现 3秒页面自动跳转</h1>
</body>
</html>
(9) Response禁止浏览器缓存
通过response头信息设置 浏览器 禁止缓存。
原理:
和禁用缓存相关头信息有三个 :
Cache-Control:no-cache
Expires:Thu, 01 Dec 1994 16:00:00 GMT ----- setDateHeader("expires",-1);
Pragma : no-cache
package ustc.lichunchun.servlet.response.demo4;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 通过Servlet禁止 缓存
*/
public class ResponseServlet4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 默认 浏览器产生 该程序缓存
// 禁用浏览器缓存
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
// 设置expires 因为日期格式很复杂
// response.setHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
// 通过 setDateHeader 为 expires设置 毫秒值 --- 从1970年1月1日 00:00:00毫秒
response.setDateHeader("expires", -1);// 已经过期
response.getWriter().println("No Cache! We can change~");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
查看缓存:IE 工具—Internet选项 —常规 — 设置 — 查看文件
实际开发中,对于Servlet生成HTML页面,会经常需要改变,所以需要禁止Servlet动态程序缓存
- 设置Expires时,通常使用 setDateHeader 为过期时间设置一个毫秒值,生成HTTP响应时,会自动转换日期字符串表示
(10) Response输出流字符编码问题
通过response 生成 客户端响应体,通过字节流和字符流两种输出方式 。
哪些情况用字节流? 哪些情况用字符流 ?
文件拷贝 ---- 字节流
分析文件内容 --- 字符流 (中文操作 字符流)
案例五:
输出中文信息——对中文信息进行编码 :
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
setCharacterEncodig 和 setContentType 区别 ?
|–setCharacterEncodig 设置响应内容编码,无法设置浏览器查看编码
|–setContentType 设置响应内容编码,同时通知浏览器查看编码
|–原理:setContentType可以在响应报文中添加 Content-Type:text/html;charset=utf-8 的头信息
代码:
package ustc.lichunchun.servlet.response.demo5;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 向浏览器输出 中文信息
*/
public class ResponseServlet5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
System.out.println("c1: "+ response.getCharacterEncoding());// 设置响应内容编码集 ,无法设置浏览器查看编码
// 需要通知浏览器 查看编码
response.setContentType("text/html;charset=gbk");// 设置响应编码 与 浏览器查看编码
System.out.println("c2: "+ response.getCharacterEncoding());//c2: gbk
// 输出中文信息--- 字符流
PrintWriter out = response.getWriter();
out.println("response向浏览器输出中文信息--setContentType中文编码!");
// 默认在方法结束后,自动关闭 response输出流,flush缓冲区内容
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
结果:
结论:开发中只需要使用setContentType就可以了。