Response
Response对象代表响应
响应由三部分组成:
- 响应行(状态码)
- 响应头
- 响应数据
用处:
- 向客户端浏览器输出中文
- 下载一个图片
- 向页面中加入动态图片(验证码)
- 控制浏览器定时刷新(使用refresh)
- 控制浏览器缓存(使用expires)
- 使用重定向
相关方法:
getStatus
setHeader
getWrite和getOutputStream
其中写数据可以分为两种方式
- 字节流 可以写任何格式的数据
- 字符流 只能写字符数据
1 如何向客户端浏览器输出中文
输出中文就涉及到编码和乱码形成的问题
不是把汉字写到客户端,而是先写到response里面
计算机或者网络之间的通信是没有汉字通信的,都是数字(二进制)通信
所以要把汉字通过一定的方式转化为数字
首先是把汉字通过编码(比如java内部的unicode编码翻译成十六进制等,然后再通过TCP/ip协议向下封装,最后转化为二进制)
1. 字节流
使用字节流,必须先把字符串转化为字节
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String dataString = "中国"; OutputStream outputStream = response.getOutputStream(); //要以字节流输出,所以要先把汉字转化为字节 outputStream.write(dataString.getBytes()); }
这种方式在浏览器上是没有问题的
但是在实际开发中,为了全球通用,一般是使用UTF-8
但是如果指定传输字节格式
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String dataString = "中国"; OutputStream outputStream = response.getOutputStream(); //指定汉字传输格式 outputStream.write(dataString.getBytes("UTF-8")); }
把汉字变成字节的过程就是把从编码表上查出汉字对应的数字,然后把数字放在一个数组里面给客户机
这里查的是UTF-8编码表
那么在浏览器上就会出现乱码(即是其他的字)
原因:
- 当把汉字定义成UTF-8时,传输的并不是汉字,而是其中对应的编码,即是数字。
- 当把数字传给浏览器时,浏览器要进行解码,但是浏览器默认的解码方式是国标gb2312
所以会解析成其他的字
servlet写给浏览器的不是汉字中国,而是它所对应的编码
解决:
- 在浏览器设置里面改动编码方式
- 在服务器代码里设定浏览器的解码方式
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //加入响应头 response.setHeader("Content-type", "text/html;charset=UTF-8"); String dataString = "中国"; OutputStream outputStream = response.getOutputStream(); outputStream.write(dataString.getBytes("UTF-8")); }
这样的话就没有问题了。
2. 字符流
因为汉字本身是字符串,所以用字符流会更方便一些
直接向response内写入一个字符流就行了,同时要注意编码
response在进行字符编码的时候默认使用的是java默认的unicode编码
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //设置response使用的码表,以控制respose以什么码表向浏览器写出数据 response.setCharacterEncoding("UTF-8"); //指定浏览器以什么码表打开服务器发送来的数据 response.setHeader("content-type","text/html;charset=UTF-8"); //以上两句的设置可以用这一句代替 //response.setContentType("text/html;charset=UTF-8"); String data = "中国"; PrintWriter out = response.getWriter(); out.write(data); }
2 如何使用response下载一个图片
public class ResponseDemo extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.读这个文件(这个文件其实就是web里面的资源,在servlet里读的话用servletcontext,在普通类中使用类加载器) //2.读资源的话有两种方式,一种是把资源作为资源流输出, 一种是使用资源的绝对地址(这种方法可以得到文件的一些信息,比如文件名) String path = this.getServletContext().getRealPath("/DownLoad/1.jpg"); String filename = path.substring(path.lastIndexOf("\\")+1); //通知浏览器怎么打开 //如果下载文件是中文名称,需要使用url编码 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filename,"UTF-8")); InputStream in= null; OutputStream out= null; try{ in = new FileInputStream(path); int len = 0; byte buffer[] = new byte[1024]; out = response.getOutputStream(); while((len = in.read(buffer))>0){ out.write(buffer,0,len); } }finally{ if(in !=null){ try{ in.close(); }catch(Exception e){ e.printStackTrace(); } } if(out !=null){ try{ out.close(); }catch(Exception e){ e.printStackTrace(); } } } }
3. 如何向页面中加入动态图片(验证码)
//构建一副图片(含有汉字的验证码图片) public class ResponseDemo2 extends HttpServlet {
//定义图片的长和宽 public static final int WIDTH = 200; public static final int HEIGTH = 50; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.首先在内存中构造一个图片 bufferimage 内存中的一张图片 //2.构造图象 //3.把内存中的图像输出到浏览器 //在内存中构建图像 BufferedImage image = new BufferedImage(WIDTH,HEIGTH ,BufferedImage.TYPE_INT_BGR); //向图像中写数据,拿到这个图像 Graphics g = image.getGraphics(); //1.设置背景色 setBackGround(g); //2.设置边框 setBorder(g); //3.画干扰线 drawRandomLine(g); //4.写随机数 //Graphics2D 可以旋转字符 drawRandomNumber((Graphics2D)g); //把图像写给浏览器,通过severlet的输出流 //先通知浏览器以什么格式打开,否则默认以文本打开 response.setContentType("image/jpeg"); //同时控制浏览器不能存放图片的缓存,不然刷新浏览器不能更新图片 response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache");
//向浏览器中输出图片 ImageIO.write(image, "jpg", response.getOutputStream()); } private void drawRandomNumber(Graphics2D g) { g.setColor(Color.RED); g.setFont(new Font("宋体",Font.BOLD, 20)); //汉字区间 ,java使用的是unicode码表,汉字在内存中存的不是汉字,都是它所对应的码值 //所有汉字都在unicode码表的4e00到9fa5
//用正则表达式测试一个字符是不是汉字 [^\u4e00-\u9fa5] //常用汉字 String base = "\u7684\u4e00\u662f\u4e86\u6211\u4e0d\u4eba\u5728\u4ed6\u6709\u8fd9\u4e2a\u4e0a\u4eec\u6765\u5230\u65f6\u5927\u5730\u4e3a\u5b50\u4e2d\u4f60\u8bf4\u751f\u56fd\u5e74\u7740\u5c31\u90a3\u548c\u8981\u5979\u51fa\u4e5f\u5f97\u91cc\u540e\u81ea\u4ee5\u4f1a\u5bb6\u53ef\u4e0b\u800c\u8fc7\u5929\u53bb\u80fd\u5bf9\u5c0f\u591a\u7136\u4e8e\u5fc3\u5b66\u4e48\u4e4b\u90fd\u597d\u770b\u8d77\u53d1\u5f53\u6ca1\u6210\u53ea\u5982\u4e8b\u628a\u8fd8\u7528\u7b2c\u6837\u9053\u60f3\u4f5c\u79cd\u5f00\u7f8e\u603b\u4ece\u65e0\u60c5\u5df1\u9762\u6700\u5973\u4f46\u73b0\u524d\u4e9b\u6240\u540c\u65e5\u624b\u53c8\u884c\u610f\u52a8\u65b9\u671f\u5b83\u5934\u7ecf\u957f\u513f\u56de\u4f4d\u5206\u7231\u8001\u56e0\u5f88\u7ed9\u540d\u6cd5\u95f4\u65af\u77e5\u4e16\u4ec0\u4e24\u6b21\u4f7f\u8eab\u8005\u88ab\u9ad8\u5df2\u4eb2\u5176\u8fdb\u6b64\u8bdd\u5e38\u4e0e\u6d3b\u6b63\u611f\u89c1\u660e\u95ee\u529b\u7406\u5c14\u70b9\u6587\u51e0\u5b9a\u672c\u516c\u7279\u505a\u5916\u5b69\u76f8\u897f\u679c\u8d70\u5c06\u6708\u5341\u5b9e\u5411\u58f0\u8f66\u5168\u4fe1\u91cd\u4e09\u673a\u5de5\u7269\u6c14\u6bcf\u5e76\u522b\u771f\u6253\u592a\u65b0\u6bd4\u624d\u4fbf\u592b\u518d\u4e66\u90e8\u6c34\u50cf\u773c\u7b49\u4f53\u5374\u52a0\u7535\u4e3b\u754c\u95e8\u5229\u6d77\u53d7\u542c\u8868\u5fb7\u5c11\u514b\u4ee3\u5458\u6d4e\u8499\u68cb\u7aef\u817f\u62db\u91ca\u4ecb\u70e7\u8bef"; int x = 10; for (int i = 0; i < 5; i++) { //得到-30到30的随机数 int degree = new Random().nextInt()%30; String ch = base.charAt(new Random().nextInt(base.length()))+""; //设置旋转幅度 g.rotate(degree*Math.PI/180,x,20); g.drawString(ch, x, 20); g.rotate(-degree*Math.PI/180,x,20); x+=30; } } private void drawRandomLine(Graphics g) { g.setColor(Color.GREEN); for(int i=0;i<8;i++){ int x1= new Random().nextInt(WIDTH); int y1 = new Random().nextInt(HEIGTH); int x2= new Random().nextInt(WIDTH); int y2 = new Random().nextInt(HEIGTH); g.drawLine(x1, y1, x2, y2); } } private void setBorder(Graphics g) { //把图形上下文设置成白色 g.setColor(Color.BLUE); //用白色填充这个矩形 g.drawRect(1,1,WIDTH-2, HEIGTH-2); } private void setBackGround(Graphics g) { //把图形上下文设置成白色 g.setColor(Color.WHITE); //用白色填充这个矩形 g.fillRect(0,0,WIDTH, HEIGTH); } }
然后把上面的图片加到一个html页面中:
<!DOCTYPE html> <html> <head> <title>register.html</title> </head> <body> <form action=""> 用户名:<input type="text"><br/> 认证码:<input type="text"><img src="/day1121/servlet/ResponseDemo2" onclick="changeImage(this)" alt="换一张" style="cursor:hand"> </form> </body> <script type="text/javascript"> function changeImage(img){ img.src = img.src +"?" + new Date().getTime(); /* 在src后面加上一个随机数的目的是使得两次的url不同,这样就不会使用缓存里的图片 */ } </script> </html>
4.控制浏览器定时刷新(使用refresh)
1. 本页面重新请求服务器
//控制浏览器定时刷新 public class ResponseDemo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ////每隔3秒重新请求一次服务器 response.setHeader("refresh", "3"); String data = new Random().nextInt(100000)+""; response.getWriter().write(data); } }
2.登陆成功后,跳转到其他页面
public class ResponseDemo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setHeader("refresh","3;url='/day1121/index.jsp"); response.getWriter().write("恭喜你,登陆成功。本浏览器将在3秒后跳转到首页,如果没有跳转,请点击<a href='www.baidu.com'>超链接</a>"); } }
5.控制浏览器缓存(使用expires)
public class ResponseDemo5 extends HttpServlet { //控制浏览器缓存 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //缓存一小时 //这样在一个小时之内请求此servlet都不会向浏览器发送请求,而是直接找系统中的页面 //IE浏览器的缓存可以直接在文件夹中查看 response.setDateHeader("expires",System.currentTimeMillis()+ 1000*3600); String dataString = "ada"; response.getWriter().write(dataString); } }
6.使用重定向
重定向的特点
- 1.客户端会向服务器发送两次请求,以为着会有两个response和request
- 2.重定向技术地址栏会发生变化
public class ResponseDemo6 extends HttpServlet { //实现请求重定向 //请求重定向能不用就不用吧,因为客户端会发送两次请求,加重服务器压力 //一定要使用请求重定向的地方: //1.登陆 //因为请求重定向会使得地址栏地址发生变化,当登陆成功后跳转到首页要在地址栏显示 //2.购物 //当servlet购买成功后,会跳转到购物车显示页面 //如果使用转发,购买成功后如果每次刷新,会重复买 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //方法1. 根据http协议 response.setStatus(302); response.setHeader("location", "/day1121/index.jsp"); //方法2.根据sun公司的封装方法 //相当于上面的两句 response.sendRedirect("/day1121/index.jsp"); } }