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 = "u7684u4e00u662fu4e86u6211u4e0du4ebau5728u4ed6u6709u8fd9u4e2au4e0au4eecu6765u5230u65f6u5927u5730u4e3au5b50u4e2du4f60u8bf4u751fu56fdu5e74u7740u5c31u90a3u548cu8981u5979u51fau4e5fu5f97u91ccu540eu81eau4ee5u4f1au5bb6u53efu4e0bu800cu8fc7u5929u53bbu80fdu5bf9u5c0fu591au7136u4e8eu5fc3u5b66u4e48u4e4bu90fdu597du770bu8d77u53d1u5f53u6ca1u6210u53eau5982u4e8bu628au8fd8u7528u7b2cu6837u9053u60f3u4f5cu79cdu5f00u7f8eu603bu4eceu65e0u60c5u5df1u9762u6700u5973u4f46u73b0u524du4e9bu6240u540cu65e5u624bu53c8u884cu610fu52a8u65b9u671fu5b83u5934u7ecfu957fu513fu56deu4f4du5206u7231u8001u56e0u5f88u7ed9u540du6cd5u95f4u65afu77e5u4e16u4ec0u4e24u6b21u4f7fu8eabu8005u88abu9ad8u5df2u4eb2u5176u8fdbu6b64u8bddu5e38u4e0eu6d3bu6b63u611fu89c1u660eu95eeu529bu7406u5c14u70b9u6587u51e0u5b9au672cu516cu7279u505au5916u5b69u76f8u897fu679cu8d70u5c06u6708u5341u5b9eu5411u58f0u8f66u5168u4fe1u91cdu4e09u673au5de5u7269u6c14u6bcfu5e76u522bu771fu6253u592au65b0u6bd4u624du4fbfu592bu518du4e66u90e8u6c34u50cfu773cu7b49u4f53u5374u52a0u7535u4e3bu754cu95e8u5229u6d77u53d7u542cu8868u5fb7u5c11u514bu4ee3u5458u6d4eu8499u68cbu7aefu817fu62dbu91cau4ecbu70e7u8bef"; 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"); } }