WEB16:Servlet学习03_Response对象
本节概要:
1.响应头的添加/设置数据
2.重定向问题
3.字符流的编码问题
4.字节流的下载问题
5.验证码生成
什么是Response对象?
其实就是服务器对浏览器的响应对象。
画张图解释一下运行过程
我们可以干什么呢?
我们可以通过servlet代码来修改response对象的响应行,响应头,响应体。从而使网页可以重定向等操作!
以下是方法的使用,都在doGet()方法中,使用response对象。
添加和设置
为响应头添加一行键值对
response.addHeader("name", "zs");
为响应头添加一行key值相同的键值对
response.addHeader("name", "ls");
我们使用抓包,抓一下看看
可以看出两个name,而没有覆盖。
为响应头添加一行value为int类型的键值对
response.addIntHeader("age", 10);
为响应头添加一行value为Date类型的键值对
response.addDateHeader("myDate", new Date().getTime());
为响应头设置一行键值对
response.setHeader("uid", "1");
为响应头在设置一行key相同的键值对
response.setHeader("uid", "2");
抓包可以看出,第一次uid被覆盖
另外set***()也有设置int和Date类型的value。
实现重定向
最初可能是这样的
//设置状态重定向
response.setStatus(302);
//设置跳转url
response.setHeader("location", "http://www.baidu.com");
其实我们有更简单的一个方法:sendRedirect(String url)发送重定向
response.sendRedirect("http://www.baidu.com");
l
另外我们可以通过js代码来实现延时跳转,主要用到了Dom的window对象下的一个周期调用函数方法setInterval()和location对象的href跳转
window.onload = function(){
var miao = document.getElementById("miao");
var time = 5;
var timer = setInterval(function(){
miao.innerHTML = time;
time--;
if(time==0){
clearInterval(timer);
location.href = "cz/login.html";
}
},1000);
}
编码问题
我们使用response对象的getWrite()方法获得向前台写数据的流,然而,当我们写入中文数据的时候会因为编码不同而报错。
例如以下:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
// 以下方法存在问题:编码表默认是iso-8859-1的编码,无法显示中文
PrintWriter out = response.getWriter();
out.write("大家好");
}
网页
这里是因为我们往流里写入时,是使用了iso-8859-1的编码表,也就是欧洲的码表。
因此,我们应该改成UTF-8,通过以下代码修改
response.setCharacterEncoding("UTF-8");
而这时可能还会显示???,这是因为我们的浏览器需要对我们编码的数据进行解码,比如中文的浏览器可能就会使用gbk来解码,而我们使用了UTF-8编码,自然找不出来了!
所以我们还要告诉浏览器使用什么码表解码!
使用下面的代码:
response.setHeader("Content-Type", "text/html;charset=UTF-8");
也许你会觉得麻烦,因此Java开发人员就添加了一个方法,直接告诉浏览器和设置编码
response.setContentType("text/html;charset=UTF-8");
字节流OutputStream
我们可以使用字符流来为网页添加文字,而遇到了下载上传图片视频等文件时我们就要用到字节流了!
字节流
ServletOutputStream out = response.getOutputStream();
也许你会觉得ServletOutputStream没见过,但其实本质还是一个OutputStream.
我们以获取web应用中的图片为例。
思路:
我们有了输出流out,它会帮我们将字节输出到响应对象response,现在缺的就是如何获取到我们的图片文件!
要获取图片文件,首先要知道它的路径,这时我们就用到了原来学习的ServletContext对象了,该对象有一个获取绝对路径的功能。
因此,我们可以拿到绝对路径了,而只需要在建立一个输入流对象就可以了。因此代码如下:
代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
ServletOutputStream out = response.getOutputStream();
//ServletContext获得绝对路径
String path = this.getServletContext().getRealPath("/img/bd.png");
InputStream in = new FileInputStream(new File(path));
//输出
int len = 0;
byte[] b = new byte[1024];
while((len=in.read(b))>0){
out.write(b, 0, len);
}
//这里我们可以只关闭我们创建的in,out Response对象会检查并自己关闭
in.close();
}
而下载其实也使用的上面的代码。
我们只是加了一些判断的代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Download</title>
</head>
<body>
<a href="/WEB07_Response/stream?filename=a.mp3" name="filename">a.mp3</a><br>
<a href="/WEB07_Response/stream?filename=a.png" name="filename">a.png</a><br>
<a href="/WEB07_Response/stream?filename=a.txt" name="filename">a.txt</a><br>
<a href="/WEB07_Response/stream?filename=a.zip" name="filename">a.zip</a><br>
</body>
</html>
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获得要下载的文件的文件名
String filename = request.getParameter("filename");
//ServletContext获得文件绝对路径
String path = this.getServletContext().getRealPath("download/"+filename);
// 获取文件的Mime值
String mime = this.getServletContext().getMimeType(path);
//设置mime值
response.setContentType(mime);
//告诉客户端不要解析该文件
response.setHeader("Content-Disposition", "attachment;filename="+filename);
// TODO Auto-generated method stub
ServletOutputStream out = response.getOutputStream();
InputStream in = new FileInputStream(new File(path));
//输出
int len = 0;
byte[] b = new byte[1024];
while((len=in.read(b))>0){
out.write(b, 0, len);
}
//这里我们可以只关闭我们创建的in,out Response对象会检查并自己关闭
in.close();
}
但是这时候如果我们的filename是中文的话,会报一个500的错误。
没错,还是因为编码的问题。
问题主要出现在这里:
String filename = request.getParameter("filename");
我们这里解码使用的是ISO-8859-1的码表,所以其实这个filename已经是乱码了。这是我们要使用Java基础学习的String重新编码
代码如下,我特地的在控制台打印出了重新编码前后的filename
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获得要下载的文件的文件名
String filename = request.getParameter("filename");
System.out.println(filename);
// 重新编码
filename = new String(filename.getBytes("ISO8859-1"),"UTF-8");
System.out.println(filename);
//ServletContext获得文件绝对路径
String path = this.getServletContext().getRealPath("download/"+filename);
// 获取文件的Mime值
String mime = this.getServletContext().getMimeType(path);
//设置mime值
response.setContentType(mime);
//告诉客户端不要解析该文件
response.setHeader("Content-Disposition", "attachment;filename="+filename);
// TODO Auto-generated method stub
ServletOutputStream out = response.getOutputStream();
InputStream in = new FileInputStream(new File(path));
//输出
int len = 0;
byte[] b = new byte[1024];
while((len=in.read(b))>0){
out.write(b, 0, len);
}
//这里我们可以只关闭我们创建的in,out Response对象会检查并自己关闭
in.close();
}
到这里,我们就完成了下载,其实在这里你会发现,中文的下载文件没有文件名
这里我们还不算完全的结束,因为浏览器兼容的问题。
我们这里还可以加入这些代码,来解决一部分的兼容性,因为浏览器的种类实在太多。我们只能兼容热门的一些浏览器
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"
+ base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
这里可能还会遇到BASE64Encoder jar找不到的麻烦请看这里>>>
全部代码
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获得要下载的文件的文件名
String filename = request.getParameter("filename");
System.out.println(filename);
filename = new String(filename.getBytes("ISO8859-1"), "UTF-8");
System.out.println(filename);
// ServletContext获得文件绝对路径
String path = this.getServletContext().getRealPath("download/" + filename);
// 获取文件的Mime值
String mime = this.getServletContext().getMimeType(path);
// 设置mime值
response.setContentType(mime);
String agent = request.getHeader("User-Agent");
String filenameEncode = null;
if (agent.contains("MSIE")) {
// IE浏览器
filenameEncode = URLEncoder.encode(filename, "utf-8");
filenameEncode = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filenameEncode = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filenameEncode = URLEncoder.encode(filename, "utf-8");
}
// 告诉客户端不要解析该文件
response.setHeader("Content-Disposition", "attachment;filename=" + filenameEncode);
// TODO Auto-generated method stub
ServletOutputStream out = response.getOutputStream();
InputStream in = new FileInputStream(new File(path));
// 输出
int len = 0;
byte[] b = new byte[1024];
while ((len = in.read(b)) > 0) {
out.write(b, 0, len);
}
// 这里我们可以只关闭我们创建的in,out Response对象会检查并自己关闭
in.close();
}
验证码生成
验证码一般都有专门的网站生成,这里简单贴一下代码!下载这个链接里的成语文件,放到WEB-INF文件夹下
提取码:shnk
配置一下web.xml就可以,访问这个Servlet就可以生成一张图片
package com.yl.servlet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 验证码生成程序
*
*
*
*/
public class CheckImgServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
// 集合中保存所有成语
private List<String> words = new ArrayList<String>();
@Override
public void init() throws ServletException {
// 初始化阶段,读取new_words.txt
// web工程中读取 文件,必须使用绝对磁盘路径
String path = getServletContext().getRealPath("/WEB-INF/new_words.txt");
try {
BufferedReader reader = new BufferedReader(new FileReader(path));
String line;
while ((line = reader.readLine()) != null) {
words.add(line);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 禁止缓存
// response.setHeader("Cache-Control", "no-cache");
// response.setHeader("Pragma", "no-cache");
// response.setDateHeader("Expires", -1);
int width = 120;
int height = 30;
// 步骤一 绘制一张内存中图片
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
// 步骤二 图片绘制背景颜色 ---通过绘图对象
Graphics graphics = bufferedImage.getGraphics();// 得到画图对象 --- 画笔
// 绘制任何图形之前 都必须指定一个颜色
graphics.setColor(getRandColor(200, 250));
graphics.fillRect(0, 0, width, height);
// 步骤三 绘制边框
graphics.setColor(Color.WHITE);
graphics.drawRect(0, 0, width - 1, height - 1);
// 步骤四 四个随机数字
Graphics2D graphics2d = (Graphics2D) graphics;
// 设置输出字体
graphics2d.setFont(new Font("宋体", Font.BOLD, 18));
Random random = new Random();// 生成随机数
int index = random.nextInt(words.size());
String word = words.get(index);// 获得成语
// 定义x坐标
int x = 10;
for (int i = 0; i < word.length(); i++) {
// 随机颜色
graphics2d.setColor(new Color(20 + random.nextInt(110), 20 + random
.nextInt(110), 20 + random.nextInt(110)));
// 旋转 -30 --- 30度
int jiaodu = random.nextInt(60) - 30;
// 换算弧度
double theta = jiaodu * Math.PI / 180;
// 获得字母数字
char c = word.charAt(i);
// 将c 输出到图片
graphics2d.rotate(theta, x, 20);
graphics2d.drawString(String.valueOf(c), x, 20);
graphics2d.rotate(-theta, x, 20);
x += 30;
}
// 将验证码内容保存session
request.getSession().setAttribute("checkcode_session", word);
// 步骤五 绘制干扰线
graphics.setColor(getRandColor(160, 200));
int x1;
int x2;
int y1;
int y2;
for (int i = 0; i < 30; i++) {
x1 = random.nextInt(width);
x2 = random.nextInt(12);
y1 = random.nextInt(height);
y2 = random.nextInt(12);
graphics.drawLine(x1, y1, x1 + x2, x2 + y2);
}
// 将上面图片输出到浏览器 ImageIO
graphics.dispose();// 释放资源
//将图片写到response.getOutputStream()中
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
/**
* 取其某一范围的color
*
* @param fc
* int 范围参数1
* @param bc
* int 范围参数2
* @return Color
*/
private Color getRandColor(int fc, int bc) {
// 取其随机颜色
Random random = new Random();
if (fc > 255) {
fc = 255;
}
if (bc > 255) {
bc = 255;
}
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
}
本节概要:
1.响应头的添加/设置数据
2.重定向问题
3.字符流的编码问题
4.字节流的下载问题
5.验证码生成
推荐阅读
-
JSP Servlet基础学习之JSP脚本中的9个内置对象
-
Servlet学习笔记6(request请求对象、response响应对象2)
-
Servlet学习笔记二—request和response对象
-
JSP Servlet基础学习之JSP脚本中的9个内置对象
-
Servlet 知识详解(五)之 —— Listener对象 监听器 学习笔记
-
Servlet 知识详解(一)之 —— ServletContext对象 和 ServletConfig对象 学习笔记
-
Servlet 知识详解(二)之 —— Request对象 和 Response对象 学习笔记
-
Servlet 知识详解(四)之 —— Filter对象 过滤器 学习笔记
-
Servlet 知识详解(三)之 —— Cookie对象 和 Session对象 学习笔记
-
WEB16:Servlet学习03_Response对象