5.request_response编程
5.1 Response对象
代表一次http响应的对象
5.1.1 设置响应行中状态码
使用
5.1.1.1关联源码
5.1.2设置响应头信息
调用 response.setHeader(name,value)
addHeader(String,String) 在原有值添加
setHeader(String,String) 替换原有值
除了以上api, 还会有 :
设置 一个 日期值
设置 一个 int值
5.1.2.1使用302+location响应头实现请求重定向
请求重定向: 访问某个资源, 某个资源 通知来访者去 定位访问 另外一个资源.
请求重定向常见的应用场景是, 登录成功的时候使用, 如果用户登录成功,那么让浏览器重新定向到网站的首页去 .
response.setStatus(302);
response.setHeader(“location”, “/day09_response/index.html”);
或
response.sendRedirect("/day09_response/index.html");
5.1.2.2 设置refresh头,实现定时刷新
使用refresh头实现页面定时的刷新.
方式一:
response.setHeader("refresh", "5;http://localhost:8080");
方式二:
<!-- 表示页面5秒后跳转到页面首页 -->
<meta http-equiv="refresh" content="5;http://localhost:8080">
实际开发过程中, 使用refresh 头刷新页面, 最多 的应用场景是 一些股票的页面, 还会这样的场景,通过 http的响应头头, 在html页面中模拟这样的头. 实现 一些特殊的功能,例如 , 页面定时跳转…
5.1.2.3 使用禁止缓存的三个头通知浏览器不要缓存
浏览器 很多时候, 会对访问的资源进行缓存, 这个时候,如果访问的资源是一个 实时都会变化的页面,那么 浏览器缓存后 就看不到 实时的最新的 值了.
所以这个时候要通知 浏览器禁止缓存 一些页面 的内容.
通知浏览器 禁止缓存可以使用 如下的三个头:
Cache-control: no-cache
Pragma: no-cache
Expires: 时间值 — 只需要是当前时间值之前的值就表示 不缓存
//设置浏览器禁止缓存
response.setHeader("cache-control", "no-cache");
response.setHeader("pragma", "no-cache");
response.setDateHeader("expires", -1);
response.getWriter().print(new Date().toLocaleString());
5.1.2.4 设置编码,调用getWriter().print()
//老外喜欢用iso8859-1,西欧的编码,不支持中文
//1.中文---二进制
// response.setCharacterEncoding("UTF-8");
//2.告诉浏览器以UTF-8的码表去解二进制数据
// response.setContentType("text/html;charset=utf-8");
//以上解决乱码,可以只写一行代码即可
//由于charset=utf-8会覆盖setCharacterEncoding的编码,所以这里只调用这一行代码即可//通过<meta>标签设置http请求头 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
response.setContentType("text/html;charset=utf-8");
//设置编码时,要先设置编码,再调用getWriter().print()
response.getWriter().print("欢饮");
5.1.3 设置响应体的内容
有getWriter() ----------- 字符流
有getOutputStream() ------ 字节流
- 在一次请求中, 不能同时去调用getWriter和 getOutputStream . 否则出现如下异常getWriter() has already been called for this response
为什么? 一次请求中, 不好控制 输出的先后顺序, 以及 不好控制编码问题, 所以 就 不让同时调用. 实际上就是要让两个方法 互斥.( 定义个布尔值, 然后 在 调用某个之后, 立刻将布尔值 更改下,然后 再 后面又 调用另外的 一方时,进行判断, 如果发现 布尔值 更改过, 直接抛 异常…) - 一般 javaio 不用了之后要关闭, 但是 由于这里是在serlvet中, 我们调用了getOutputStream , getWriter 之后, 如果没有关闭,服务器 会检查 是否已经, 没有关, 就 会自己去关闭. 调用close的时候,应该会调用flushBuffer
5.1.4 使用contentType生成一个xml格式文件输出到浏览器
//setContentType告诉浏览器打过去的数据是什么格式的数据类型
//需要查到xml文件对应的mime类型
response.setContentType("application/xml");
response.getWriter().println("<world>");
response.getWriter().println("<china>");
response.getWriter().println("<beijing>beijing</beijing>");
response.getWriter().println("</china>");
response.getWriter().println("</world>");
5.1.5 生成验证码图片
//首先需要在内存中构建一张图片出来
BufferedImage bf=new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics=(Graphics2D) bf.getGraphics();
Color color=new Color(203,232,225);
//设置背景颜色
graphics.setColor(color);
graphics.fillRect(0, 0, WIDTH, HEIGHT);
String base="ABCDEFGHIJKLMN";
Random random=new Random();
//状态机:如果之前设置过相应属性,下次没有调用相应API时,其状态不会发生改变
graphics.setColor(Color.RED);
graphics.setFont(new Font("楷体",Font.BOLD,18));
int m=13;
for(int i=0;i<4;i++) {
int index=random.nextInt(base.length());
char charAt=base.charAt(index);
//-30-------30
int jiaodu=random.nextInt(60)-30;
double theta=jiaodu*Math.PI/180;
graphics.drawString(charAt+"", m, 15);
graphics.rotate(theta, m, 15);
m+=20;
}
for(int i=0;i<4;i++) {
int x1=random.nextInt(WIDTH);
int y1=random.nextInt(HEIGHT);
int x2=random.nextInt(WIDTH);
int y2=random.nextInt(HEIGHT);
graphics.drawLine(x1, y1, x2, y2);
}
ImageIO.write(bf,"png",response.getOutputStream());
5.2 Request对象
Request对象代表着 一次客户端的http的请求, http请求分为请求行,请求头,请求体, 一次请求中所有的数据都会被封装在这个request对象中, 其中这个request对象是 服务器在调用Servlet的service方法的时候,传递进来的.也是就是说 服务器创建好了这个对象, 并且将所有的数据封装到了这个对象中, 所以如果要获得来自客户端请求的数据,通通找 request .
5.2.1 获取客户机信息
String addr = request.getRemoteAddr();
StringBuffer requestURL=request.getRequestURL();
String requestURI=request.getRequestURI();
String ip = request.getRemoteAddr();
String method=request.getMethod();
String ContextPath=request.getContextPath();
5.2.2 referer 实现资源防盗链
response.setContentType("text/html;charset=UTF-8");
String referer=request.getHeader("referer");
if(referer==null||!"http://localhost:8080/day09/1.html".equals(referer)) {
//如果进来说明为盗链
response.getWriter().println("盗链");
}else {
response.getWriter().println("点击链接进来");
}
5.2.3 Get和post的乱码解决
获得请求的参数, 由于 get和post请求方式是不一样的, 传递的参数 会放在不同的地方. 所以 要分开去 讨论
//get()方法
String value = request.getParameter("username");
//采用迂回的方式
//重新将乱码的值按照ISO8859-1的编码编回去
// byte[] bytes=value.getBytes("ISO8859-1");
//再以UTF-8的编码进行解码
// value=new String(bytes,"UTF-8");
//post()方法
//覆盖了请求体中的编码方式
request.setCharacterEncoding("UTF-8");
String value = request.getParameter("username");
5.2.4 获得复杂表单数据
form.html
<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="hobbies" value="游泳">游泳
<input type="checkbox" name="hobbies" value="打毛衣">打毛衣
<input type="checkbox" name="hobbies" value="打球">打球
<input type="checkbox" name="hobbies" value="跑步">跑步
</td>
</tr>
<tr>
<td>城市:</td>
<td>
<select name="city">
<option value="深圳">深圳 </option>
<option value="北京">北京 </option>
<option value="上海">上海 </option>
</select>
</td>
</tr>
servlet.java
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
System.out.println(username);
String[] values = request.getParameterValues("hobbies");
for(String vl:values) {
System.out.println("爱好:"+vl);
}
5.3 Request&Response
5.3.1 重定向与转发的区别
转发与重定向的区别
- 1.请求重定向是找response,而转发是找request
- 2.重定向有两次请求,转发只有一次请求
- 3.重定向浏览器地址栏发生变化,转发浏览器地址栏不发生变化
- 4.重定向地址栏发生变化,用户可以感知到访问了其他资源,而转发是服务器内部的行为,用户是不知道的
- 5.重定向是可以指向互联网上的任何资源的,而转发只能指向服务器的内部资源
转发与数据共享:
A Servlet
//使用request实现数据的共享
request.setAttribute("name", "张三");
//不想处理来访者的请求
//将请求转发给B servlet去处理,转发指向服务器内部资源
//写的时候必须要写/,这个/表示web应用
request.getRequestDispatcher("/request2").forward(request, response);
B Servlet
String name=(String) request.getAttribute("name");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("B Servlet------"+name);
请求重定向:
response.sendRedirect("http://localhost:8080");
应用场景:
用户登录的时候:
成功: 重定向到网站的首页 去 … Response.sendRedirect(“/day10/index.html”);
失败: 使用转发的技术, 再次回到 登录的页面, 并且 在登录的页面 提示友好错误信息
request.getRequestDispatcher("/login.jsp").forward(request, response);
5.3.2 域对象
在serlvet中只要涉及到域对象的时候 应该想到 具有如下的特点:
1.容器
2.有范围大小
3.SetAttribute(String name, Object obj)
getAttribute(name)
removeAttribute(name);
serlvetContext 域对象 :
范围是 web应用的范围内, 可以使用 如上的 三个方法 来实现 数据的共享
request域对象:
范围是一次请求的范围内, 可以 使用 如上的三个 方法来实现数据共享
Session域对象:
范围是 **一个浏览器 (一次会话 )**的范围内, 可以 使用 如上的三个 方法来实现数据共享
按照从小到大的顺序排个序:
request < session <servletContext
- 到底什么时候 用哪个 ?
能够用小的,就不 用大的 .
统计网站的访问次数--- 用serlvetContext对象
实现用户登录成功的时候, 存储登录的用户, 在网站的首页显示出来------- 用session
在登录失败的时候, 取出友好的错误提示信息------------ 用 request