我在我的应用程序中遇到问题,其中我有一个作为 JSF 自定义标签构建的验证码组件:
在我的 JavaEE 6 webapp 中,我使用:JSF 2.1 + Jboss Richfaces 4.2.3 + EJB 3.1 + JPA 2.0 + PrettyFaces 3.3.3
我有一个 JSF2 自定义标签,即:
<tag>
<tag-name>captcha</tag-name>
<source>tags/captcha.xhtml</source>
</tag>
在我的名为 accountEdit.xhtml 的 XHTML 页面中,我显示了验证码:
<ui:fragment rendered="#{customerMB.screenComponent.pageName eq 'create'}">
<div class="form_row">
<label class="contact"><strong>#{msg.captcha}:</strong>
</label>
<atl:captcha></atl:captcha>
</div>
</ui:fragment>
在 captcha.xhtml 中:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<table border="0">
<tr>
<td>
<h:graphicImage id="capImg" value="#{facesContext.externalContext.requestContextPath}/../captcha.jpg" />
</td>
<td><a4j:commandButton id="resetCaptcha" value="#{msg.changeImage}" immediate="true" action="#{userMB.resetCaptcha}" >
<a4j:ajax render="capImg" execute="@this" />
</a4j:commandButton></td>
</tr>
<tr>
<td><h:inputText value="#{userMB.captchaComponent.captchaInputText}" /></td>
</tr>
</table>
</ui:composition>
在我的 web.xml 中,我配置了一个 CaptchaServlet 来处理在运行时生成验证码的请求:
<servlet>
<servlet-name>CaptchaServlet</servlet-name>
<servlet-class>com.myapp.web.common.servlet.CaptchaServlet</servlet-class>
<init-param>
<description>passing height</description>
<param-name>height</param-name>
<param-value>30</param-value>
</init-param>
<init-param>
<description>passing width</description>
<param-name>width</param-name>
<param-value>120</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CaptchaServlet</servlet-name>
<url-pattern>/captcha.jpg</url-pattern>
</servlet-mapping>
我的 CaptchaServlet 实现:
public class CaptchaServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 6105436133454099605L;
private int height = 0;
private int width = 0;
public static final String CAPTCHA_KEY = "captcha_key_name";
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
height = Integer
.parseInt(getServletConfig().getInitParameter("height"));
width = Integer.parseInt(getServletConfig().getInitParameter("width"));
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse response)
throws IOException, ServletException {
// Expire response
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Max-Age", 0);
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = image.createGraphics();
Hashtable<TextAttribute, Object> map = new Hashtable<TextAttribute, Object>();
Random r = new Random();
String token = Long.toString(Math.abs(r.nextLong()), 36);
String ch = token.substring(0, 6);
Color c = new Color(0.6662f, 0.4569f, 0.3232f);
GradientPaint gp = new GradientPaint(30, 30, c, 15, 25, Color.white,
true);
graphics2D.setPaint(gp);
Font font = new Font("Verdana", Font.CENTER_BASELINE, 26);
graphics2D.setFont(font);
graphics2D.drawString(ch, 2, 20);
graphics2D.dispose();
HttpSession session = req.getSession(true);
session.setAttribute(CAPTCHA_KEY, ch);
OutputStream outputStream = response.getOutputStream();
ImageIO.write(image, "jpeg", outputStream);
outputStream.close();
}
}
当我在 Glassfish 3.1.1 上运行此应用程序时,在渲染时调用 Servlet 的 doGet() 方法
对于呈现的 HttpServlet doGet() 方法:
<h:graphicImage id="capImg" value="#{facesContext.externalContext.requestContextPath}/../captcha.jpg" />
doGet() 只为 Google Chrome 呈现一次,因此可以正确呈现。
对于 Firefox 和 IE,doGet() 渲染两次更新验证码密钥,但不更新页面上绘制的验证码图像。
如果有人可能知道什么可以解决这个问题,以及为什么 Chrome 的这种行为不同于其他浏览器,请告诉我。
提前致谢!