日期:2014-05-16  浏览次数:20635 次

Linux/Unix + RESIN/Tomcat 验证码无法显示的问题(ZT)

最近公司项目开发中遇到的一个问题,整理一下,和大家分享。

??? 验证码无法显示的问题,验证码的代码就是google上查找到的最常见的代码,服务器采用resin部署于linux或unix。不是常见的out.clear()问题,这次的问题发现在一个我压根就没有想到的地方,profile DISPLAY 环境变量。?

??? 1) 问题描述:
??? 登录页面等有验证玛显示的页面,通常可以正确显示验证码图片,但是在某些情况下发现验证码图片无法显示,并且目前只发生在linux/unix平台,windows下正常.而且和resin/jdk版本无关.

??? bug的直接表现是表现为ie下是红叉,firefox下无实现.将验证码图片的地址在ie输入框中输入,则页面报错:

Java代码 复制代码
  1. 500?Servlet?Exception ??
  2. java.lang.NoClassDefFoundError ??
  3. ????at?java.lang.Class.forName0(Native?Method) ??
  4. ????at?java.lang.Class.forName(Class.java:164) ??
  5. ????at?java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68) ??
  6. ????at?java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1141) ??
  7. ????????at?com.asiainfo.aimc.wmail.action.CreateImageServlet.doGet(CreateImageServlet.java:104)??
500 Servlet Exception
java.lang.NoClassDefFoundError
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:164)
	at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68)
	at java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1141)
        at com.asiainfo.aimc.wmail.action.CreateImageServlet.doGet(CreateImageServlet.java:104)



??? 这里的java.lang.NoClassDefFoundError 极其误导人,一直以为是CLASSPATH或者jar包的问题,所以反复检查resin和jdk版本。
?? 始终无法找到问题,只好尝试追查jdk源码,看到底发生了什么。

2) jdk源码追查

?? 调用的servlet:
BufferedImage bi = new BufferedImage(...)
Graphics2D g = bi.createGraphics();

?? 查jdk: BufferedImage.createGraphics():
GraphicsEnvironment env =
??? GraphicsEnvironment.getLocalGraphicsEnvironment();

?? 再查GraphicsEnvironment.getLocalGraphicsEnvironment:
String nm = (String) java.security.AccessController.doPrivileged
(new sun.security.action.GetPropertyAction
("java.awt.graphicsenv", null));
......
localEnv = GraphicsEnvironment) Class.forName(nm).newInstance();
......
??? 问题应该和nm有关,这里明显是一个类似工厂模式的设计,"java.awt.graphicsenv"到nm 然后Class.forName() 生成GraphicsEnvironment对象。
??? 由于代码在jdk中,不方便修改,因此单独将这些代码提出来到简单的测试类 Test.java:

3) 测试代码分析

Java代码 复制代码
  1. public?class?Test?{ ??
  2. ????public?static?void?main(String[]?args)?{ ??
  3. ????????String?nm?=?(String)?java.security.AccessController.doPrivileged ??