1

我在我的应用程序中遇到问题,其中我有一个作为 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 的这种行为不同于其他浏览器,请告诉我。

提前致谢!


具有大量参数的最佳编译方式(一种 cpp 程序)

这些天我正在学习opengl,并且正在从命令行编译(我不想使用IDE,因为我习惯了VIM)。编译 opengl 文件可能很麻烦,假设我有一个名为 hello.cpp 的文件,为了快速编译和运行,我必须这样做:

g++ -framework GLUT -framework OpenGL -framework Cocoa hello.cpp & ./a.out

由于我正在学习 opengl,因此我将使用许多不同的文件进行测试,并且一直键入上述命令对我来说是不可行的。我想要的是这样的:

some_command % & ./a.out

some_command最好是一些常用的(如g++、make),%是文件名。

我认为 makefile 可能是一个可能的解决方案,所以我继续学习了 makefile 但它似乎适用于特定名称;有一些方法可以将参数传递给makefile,但对我来说似乎还是太麻烦了(我必须手动输入 ARGUMENT=filename 部分)。

另外我认为 shell 脚本可能是一个很好的解决方案。唯一的后备是我必须为 shell 脚本自定义一个名称。

我想知道是否有更好的方法让我快速编译和运行 opengl cpp 文件

非常感谢。

4

2 回答 2

3

浏览器正在缓存响应。您避免这种情况的尝试是不完整且不正确的:

response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Max-Age", 0);

请参阅如何在所有浏览器中控制网页缓存?对于正确的集合:

response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.

此外,为了使其更健壮,将带有当前时间戳的查询字符串(以毫秒为单位)添加到图像 URL。这是一个示例,前提是您有一个java.util.Date名为托管 bean 的实例now

<h:graphicImage id="capImg" value="#{request.contextPath}/../captcha.jpg?#{now.time}" />

(请注意,我还简化了获取请求上下文路径的方法,我只是不明白如果你去域根目录有什么用../

于 2013-03-27T12:11:33.500 回答
0

我找到了一个解决方案,不是最佳解决方案,但它有效,这里是:

验证码.xhtml

<table border="0">
    <tr>
        <td>
            <h:graphicImage url="#{request.contextPath}/../jcaptcha"/>
        </td>
        <td>
            <input type='text' name='j_captcha_response' value='' />
        </td>
    </tr>
</table>

CaptchaServlet doGet 方法:

    protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {

        byte[] captchaChallengeAsJpeg = null;
        // the output stream to render the captcha image as jpeg into
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
        // get the session id that will identify the generated captcha.
        //the same id must be used to validate the response, the session id is a good candidate!
        String captchaId = httpServletRequest.getSession().getId();
            // call the ImageCaptchaService getChallenge method
            BufferedImage challenge =
                    CaptchaServiceSingleton.getImageChallengeForID(captchaId,
                            httpServletRequest.getLocale());
            // a jpeg encoder
            JPEGImageEncoder jpegEncoder =
                    JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (CaptchaServiceException e) {
            httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();

        // flush it in the response
        httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
        httpServletResponse.setHeader("Pragma", "no-cache");
        httpServletResponse.setDateHeader("Expires", 0);
        httpServletResponse.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream =
                httpServletResponse.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }

创建 CaptchaServiceRequestSingleton.java

    package com.myapp.web.common.listener;

    import java.awt.image.BufferedImage;
    import java.util.HashMap;
    import java.util.Locale;

    import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
    import com.octo.captcha.service.image.ImageCaptchaService;

public class CaptchaServiceSingleton {

    private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService();
    private static final int MAX_CACHE_SIZE = 200;
    private static HashMap<String, BufferedImage> captchaImgCache = new HashMap<String, BufferedImage>();

    public static ImageCaptchaService getInstance(){
        return instance;
    }

    public static BufferedImage getImageChallengeForID(String id, Locale locale) {
        if (captchaImgCache.containsKey(id)) {
            return captchaImgCache.get(id);
        } else {
            BufferedImage bImage = instance.getImageChallengeForID(id, locale);

            // if limit reached reset captcha cache
            if (captchaImgCache.size() > MAX_CACHE_SIZE) {
                captchaImgCache = new HashMap<String, BufferedImage>();
            }

            captchaImgCache.put(id, bImage);
            return bImage;
        }
    }

    public static void resetImageChallengeForID(String id) {        
        if (captchaImgCache.containsKey(id)) {      
            captchaImgCache.remove(id);
        }               
    }

}

单击“创建帐户”按钮时,验证码被重置:

CustomerMB.openCreateCustomerAccount():

public String openCreateCustomerAccount() {
    customerAccountEditVO = new CustomerAccountVO();
    screenComponent.setPageName(NameConstants.CREATE);
    getUserMB().resetCaptcha();
    return null;
}

在 UserMB.resetCaptcha() 中:

public String resetCaptcha() {
    CaptchaServiceSingleton.resetImageChallengeForID(JSFUtil.getRequest().getRequestedSessionId());     
    return null;
}

也许这不是完美的解决方案,但至少它适用于所有浏览器。

于 2013-03-29T22:25:04.003 回答