Servlet中应该如何向用户输出数据呢?在doGet和doPost方法的参数中,HttpServletRequest代表的是http请求,而HttServletResponse代表的是http响应。想要获取请求中的信息时使用HttpServletRequest对象,而有数据需要发送给客户端时,就要用到HttpServletResponse对象了。
虽然我们经常简称为response,实际上是ServletResponse接口,其中定义了很多和响应对象相关的方法,HttpServletResponse是ServletResponse接口的子接口,在ServletResponse的基础上增加了很多和http协议相关的方法。如图-40所示:
图-40
setStatus(int sc)
setStatus(int sc, String sm)
setIntHeader(String name, int value)
setHeader(String name, String value)
setDateHeader(String name, long date)
PrintWriter getWriter()
ServletOutputStream getOutputStream();
查询api,在Response向外输出数据的方法有如下两个:
PrintWriter getWriter()
ServletOutputStream getOutputStream();
其中getWriter获取的是字符流,可以输出字符数据到客户端。
getOutputStream获取的是字节流,可以输出字节数据到客户端。
我们现在要将字符数据发送给客户端,可以调用getWriter方法向其中输出数据
经测试可以正确的输出。如图-41所示:
图-41
接着我们测试中文。发现输出时产生了乱码。如图-42所示:
图-42
这个乱码是如何产生的呢?乱码的产生大多是由于编码和解码时的码表不同产生的。
那么服务器是以什么码表来发送数据呢?我们发现乱码是以“?”的形式出现的。根据我们的经验,这种问题多半是由ISO8859-1编码导致的。
确实是的,如果不指定,服务器默认将用iso8859-1进行编码发送数据。浏览器用什么码表打开呢?一般来说如果不指定,浏览器默认会用所在的操作系统的平台码,我们当前的中文系统中,默认就是使用GB2312作为解码码表的。
首先iso8859-1中没有中文,对于无法表示的字符,iso8859-1会用“?”来替代,所以真正发送给浏览器的数据其实是“?”,世界上所有的码表都默认兼容iso8859-1,所以gb2312认识,显示为了“?”。如图-43所示:
图-43
在解决这个问题时,可以通过设置response.setCharacterEncoding(“gbk”)来指定服务器发送数据时使用的码表。同时要注意,此行代码必须出现在任何输出数据的代码之前,如果在这行代码之前已经有任何数据写入给了response,则此行代码无效。
设置过后再重新测试。发现仍然是乱码,但不再是“??”而是变成了“涓浗”。如图-44所示:
图-44
这种类型的乱码是怎么发生的呢?我们接着分析。服务器用utf-8发送数据给浏览器,而浏览器用平台码(当前为gbk)gbk打开自然产生了乱码。如图-45所示:
图-45
这种乱码的产生是由于浏览器没有使用正确的编码打开造成的,那么我们该如何控制浏览器用指定码表打开数据呢?
在http协议中有一个响应头叫做Content-Type可以用来通知浏览器当前服务器发送的数据的格式,如果是字符格式的数据还可以指定解析时使用的码表。所以我们可以通过如下方法通知浏览器用指定码表打开发送的数据,代码如下,经测试没有乱码。
我们通过response.setHeader("Content-Type", "text/html;charset=utf-8");通知服务器发送数据时的码表。
通过response.setCharacterEncoding("utf-8");通知浏览器解析时使用的码表。
两码相同就不会有乱码了。
如图-46所示:
图-46
另外response提供了setContentType()快捷方法,在它的底层,会同时做上面两件事,所以可以一行代码解决response产生的乱码问题。如图-47所示:
图-47
(1)getOutputStream和getWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。 (2)Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。 (3)Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎tomcat将调用close方法关闭该输出流对象。