4章 out内置对象

 

  前面提到了dqm之所以简单实用很大一部分就是由于提供了功能强大的六大内部对象,从本章开始我们将逐一介绍这些内置对象,本章先介绍out对象。

out对象是用来控制送出给客户端的信息。

 

 

4.1 printprintln方法

out对象的printprintln是二个最主要的方法,主要作用就是向客户端输出字符型数据。

 

1.       public void print(String content, String charsetName) throws IOException

按指定的字符集向客户端输出一串字符。

参数:content向客户端输出的字符串。

     charsetName指定content的字符集,比如BIG-5UTF-8GBK等。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

2.       public void print(String content) throws IOException

按默认的字符集向客户端输出一串字符。默认的字符集是指webconfig.xmlsystemSetdataEnc所制定的值(参见2.1节)。

参数:content向客户端输出的字符串。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

3.       public void print(boolean content) throws IOException

向客户端输出一个布尔值。

参数:content向客户输出的布尔值

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

4.       public void print(char content) throws IOException

向客户端输出一个字符值。

参数:content向客户输出的字符值。

异常:如果输出中遇到问题则此方法会抛出IOException异常

 

5.       public void print(char[] content) throws IOException

向客户端输出一个字符数组。

参数:content向客户输出的字符数组。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

6.       public void print(double content) throws IOException

向客户端输出一个双精度浮点数。

参数:content向客户输出的双精度浮点数。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

7.       public void print(float content) throws IOException

向客户端输出一个单精度浮点数。

参数:content向客户输出的单精度浮点数。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

8.       public void print(int content) throws IOException

向客户端输出一个整型数。

参数:content向客户输出的整型数。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

9.       public void print(long content) throws IOException

向客户端输出一个长整型数。

参数:content向客户输出的长整型数。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

10.   public void print(Object content) throws IOException

向客户端输出一个对象。

参数:content向客户输出的对象。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

以上方法还有一个简化方法,即<%=content%>,此语句等于<%out.print(content);%>content可以是字符、整型等上面出现过的类型。

  同时和以上方法具有相同参数的println方法,唯一的区别就是换行输出。

看一个列子print_test.dqm,源程序如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<pre>

 

<%

out.println("你好", "GBK");

out.println("你好");

out.println(true);

out.println('');

char[] chars = {'',''};

out.println(chars);

out.println(3.14d);

out.println(3.14f);

out.println(3);

out.println(314l);

Object obj = new Object();

out.println(obj);

%>

 

</pre>

 

输出结果为:

你好

你好

true

你好

3.14

3.14

3

314

java.lang.Object@87a5cc

 

 

4.2 write方法

out对象的write方法主要用于向客户端输出二进制信息,有时可能在数据库中保存了二进制信息,就可以用这些方法输出。例如从数据库中显示图片的信息。

 

1.       public void write(byte[] content, int off, int len) throws IOException

向客户端输出byte数组,输出的长度由len参数指定,输出的开始位置由off参数指定。

参数:content向客户输出的byte数组。

   off表示从content第几项开始输出。

   len表示需要输出多少byte

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

2.       public void write(byte[] b) throws IOException

向客户端输出byte数组。

参数:content向客户输出的byte数组。

异常:如果输出中遇到问题则此方法会抛出IOException异常。

 

 

4.3 数据压缩方法

前面在配置webconfig.xml文件中提到过主机和虚拟主机都有needCompress项用于配置动态资源是否压缩后输出(参见2.42.5节)。但是利用needCompress进行配置有个缺点,即动态文件输出要么全部都开启压缩,要么全部都关闭,缺乏灵活性,3.2节中我们得知page指令的compress项可以单独设置当前动态文件是否开启压缩,不过即使这样似乎还是缺乏灵活性,于是我们在out对象中加入了更加灵活的控制压缩方法语句。

 

1.       public boolean setEnableCompress(boolean vaule)

设置当前动态文件向客户端输出是否需要压缩。如果在动态文件中使用了本方法则以当前设定的值为准,如果在动态文件中未出现过此方法则以主机或虚拟主机的needCompress配置项为准。当多次出现此方法则以最后一次设定的值为准。本方法必须在开起缓存的情况下才能使用(开启缓存请参见3.2节的page指令),如不开启缓存则只能使用webconfig.xml文件的needCompress配置项来指定是否开启压缩。本方法最大用处就是实时判断是否需要压缩输出,比如本次输出内容很多则可以选择压缩(输出内容大小可以用getBufSize方法来检查,此方法4.4节中将会介绍),如输出内容很少那也就没什么必要压缩了。

参数:value如果需要压缩此值为true,否则为false

返回:是否真正开启了压缩。因为有些情况比如浏览器不支持解压缩则即使指定开启压缩功能但是实际上还是无法进行压缩输出。本返回项就是查看在设置后真正的压缩状态。

 

注意:此方法与page指令的compress项最大不同在于本方法可以使用boolean变量(即可以条件性指定),而在指令中是不能使用变量的。同时本方法需要开启缓存才能使用,在未开启的情况下则只能使用指令设置。

 

 

2.       public boolean getIsEnableCompress()

查看当前真正的压缩状况。本方法返回的值与setEnableCompress方法返回的值是一样的,设立此方法的原因是便于用户随时查看压缩状况。

返回:是否真正开启了压缩。因为有些情况比如浏览器不支持解压缩则即使指定开启压缩功能但是实际上还是无法进行压缩输出。本返回项就是查看当前真正的压缩状态。

 

3.       public String getCompressName()

返回当前访问的客户端和服务器端都具有即双方都能够理解的压缩格式的名字,比如客户端支持gzip压缩格式,服务器端也支持gzip压缩格式,则返回gzip。如果客户端支持zip压缩格式而服务器端却只支持gzipdeflate压缩格式,则返回no。有时双方都同时支持好几种压缩格式,则服务器会选择首选默认的压缩格式进行传输。目前服务器只支持gzipdeflate二种压缩格式,而gzip是首选的压缩格式,这就是说如果客户端即支持gzip也支持deflate那么还是返回gzip,因为gzip是首选项。同时注意此返回值与压缩是否开启无关。

返回:如果双方不具有都能支持的压缩格式则返回no,否则返回双方都能支持的压缩格式名字比如gzip

 

看一个列子compress.dqm,源程序如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<%@ page buffer="true"%>

 

<pre>

 

开启压缩输出

<%

out.setEnableCompress(true);

%>

当前是否真正启用压缩:<%=out.getIsEnableCompress()%>

浏览器支持的压缩格式:<%=out.getCompressName()%>

 

关闭压缩输出

<%

out.setEnableCompress(false);

%>

当前是否真正启用压缩:<%=out.getIsEnableCompress()%>

浏览器支持的压缩格式:<%=out.getCompressName()%>

 

</pre>

 

当所使用的浏览器支持gzip压缩处理时输出结果为:

1

2

3

4

5

6

7

8

9

开启压缩输出

 

当前是否真正启用压缩:true

浏览器支持的压缩格式:gzip

 

关闭压缩输出

 

当前是否真正启用压缩:false

浏览器支持的压缩格式:gzip

 

源程序第7行用于设置开启压缩功能,接下来源程序第9行用于查看开启压缩功能后真正的压缩状态,因为我们使用的浏览器支持压缩传输,所以结果第3行中显示了真正开启了压缩功能。之后源程序第14行关闭了压缩功能,而源程序第16行用于查看关闭压缩后的状态,可以从结果第8行看出的确是关闭了压缩功能。从结果第49行可以看出不管是否启用压缩功能,浏览器都是支持gzip压缩的,因为我们使用的浏览器是支持压缩的。

 

  以上输出结果有可能在不同环境下不同,因为有些浏览器不支持压缩格式,即使支持也有可能不支持gzip压缩格式。

 

 

4.4 缓存相关方法

上一节我们又一次提到了缓存,setEnableCompress方法必须开启缓存才能使用,那么缓存到底有何作用呢?如果不开启缓存则是边执行边输出,而开启缓存则是边执行边将输出的内容放入缓存,等全部执行完毕后则将缓存中的内容全部输出至客户端。所以缓存的好处是在执行过程中即全部执行完毕前可以修改执行后输出的内容,因为这些内容在全部执行完毕输出至客户端前都暂存在缓存中。不过缓存需要暂用内存,且如果执行过程相当长则客户端将等待很长的执行过程全部完毕后才能看到内容。out对象中有二个方法是与操作缓存有关的。

 

1.       public int getBufSize()

返回当前缓存的大小。

返回:如果没有开启缓存则返回-1,如果开启缓存则返回当前缓存的大小。

 

2.       public void clear()

清除当前缓存中的数据。如果没有开启缓存则此方法不做任何事情。

 

看一个列子buffer.dqm,源程序如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<%@ page buffer="true"%>

 

 

输出内容1

 

<%out.clear();%>

 

<pre>

清除当前缓存

当前缓存容量:<%=out.getBufSize()%>

 

输出内容2

当前缓存容量:<%=out.getBufSize()%>

</pre>

 

输出结果为:

清除当前缓存

当前缓存容量:39

 

输出内容2

当前缓存容量:70

 

从上面输出结果来看源程序25行的内容都没有被输出,因为在第6行清除了之前所有的内容。源程序710行的输出内容大小为39713行的输出内容大小为70,这在结果中都显示出来了。

 

 

4.5 直接数据输出

内置的out对象是继承了java.io.OutputStream这个类,为此根据java的多态原理out可以直接看作是java.io.OutputStream类型。

  我们来看一个例子,screen.dqm用于截取服务器端的屏幕,然后输出至客户端。源程序如下:

1

2

3

4

5

6

7

8

 

9

10

 

11

12

13

14

15

16

17

18

<%@page ContentType="image/png" buffer="true"

import="java.awt.*; java.awt.image.BufferedImage; javax.imageio.ImageIO"%><%

 

try {

  Toolkit toolkit = Toolkit.getDefaultToolkit();

  Dimension ScreenDim = toolkit.getScreenSize();

  Robot rb = new Robot();

  BufferedImage img = new BufferedImage(ScreenDim.width, ScreenDim.height, BufferedImage.TYPE_BYTE_GRAY);

  Graphics2D gImg = img.createGraphics();

  BufferedImage cutimg = rb.createScreenCapture(new Rectangle(ScreenDim.width,ScreenDim.height));

  gImg.drawImage(cutimg, null, 0, 0);

  ImageIO.write(img, "png", out);

}

catch (Exception e) {

  e.printStackTrace();

}

out.setEnableCompress(false); //也可以启用压缩out.setEnableCompress(true);

%>

 

执行结果会看到服务器端当前截图。源程序在第7行初始化了java机器人对象。第89行初始化了一个与服务器桌面大小一样的黑白画布,用以存放截图。第10行就用前面的java机器人对服务器桌面进行截图,接下来11行将截图存入先前初始化的黑白画布中,最后12行将画布输出至客户端。

12ImageIOwrite方法如下:

public static boolean write(RenderedImage im, String formatName, OutputStream output)

throws IOException

可以看到第三个参数的类型是OutputStream,而我们在这里直接传入了内置变量out,程序运行一切正常,这就证实了我们前面所说的out内置变量可以直接看成是OutputStream类型的。

 

注意:screen.dqm源程序第2行的末尾的"%><%"必须紧靠,否则图片就无法显示。因为如果没有紧靠则会有字符输出,如"%> <%"中的空格字符就会输出,这样图片中就会含有非法数据,以至于图片无法正确显示。linuxunix必须在图形界面下才能使用本例。