zoukankan      html  css  js  c++  java
  • 使用JCaptcha生成验证码

    在项目里用JCaptcha添加了验证码. 中间调试费了很多时间, 这里直接把步骤和结果的源代码贴出来吧.

    首先要到JCaptcha的官网去下载jar包, 目前使用 jcaptcha-1.0-all.jar 这个就够了, 如果你的lib中没有 commons-collections-3.2.1.jar 的话, 需要去 Apache Collections 网站下一个, 因为生成时使用的fasthashmap依赖于这个jar.

    JCaptcha 官网上 java doc已经已经更新至2.0alpha版, 但是发布的jar还是1.0, 所以java doc中提到的一些engine在jar中是没有的, 一些deprecated的类在1.0中依然需要使用.

    JCaptcha 官网上提供了一个最简单的5分钟速成样例, 直接使用DefaultManageableImageCaptchaService构建验证图.

    因为默认的验证图很难辨认, 所以还是需要自己定制一下, 以适应自己项目的需求.

    首先是扩展出自己的ImageCaptchaEngine, 命名为 CaptchaImageEngine.java . 这里借鉴了几个网络上前辈提供的例子, 做了一些修改

    public class CaptchaImageEngine extends ListImageCaptchaEngine
    {
        public static final Integer WORD_MIN_LENGTH = new Integer(4);
        public static final Integer WORD_MAX_LENGTH = new Integer(4);
    
        public static final Integer IMAGE_WIDTH = new Integer(160);
        public static final Integer IMAGE_HEIGHT = new Integer(50);
    
        public static final Integer FONT_MIN_SIZE = new Integer(30);
        public static final Integer FONT_MAX_SIZE = new Integer(35);
    
        protected void buildInitialFactories()
        {
            WordGenerator wordGenerator = (new RandomWordGenerator("23456789ABCDEFGHJKMNPQRSTUVWXY"));
    
            BackgroundGenerator backgroundGenerator = new UniColorBackgroundGenerator(IMAGE_WIDTH, IMAGE_HEIGHT);
    
            Font[] fontsList = new Font[]{Font.decode("Arial"), Font.decode("Georgia"), Font.decode("Verdana"), Font.decode("Courier New")};
            FontGenerator fontGenerator = new RandomFontGenerator(FONT_MIN_SIZE, FONT_MAX_SIZE, fontsList);
    
            RandomRangeColorGenerator cgen = new RandomRangeColorGenerator(
                    new int[] { 0, 128 },
                    new int[] { 0, 128 },
                    new int[] { 0, 196 }
                );
    
            TextDecorator[] textdecorators = new TextDecorator[]{new BaffleTextDecorator(new Integer(1), Color.WHITE)};
    
            TextPaster textPaster = new DecoratedRandomTextPaster(
                    WORD_MIN_LENGTH,
                    WORD_MAX_LENGTH,
                    cgen,
                    textdecorators
                );
    
            WaterFilter water = new WaterFilter();
            water.setAmplitude(5d);//振幅
            water.setAntialias(true);//锯齿或平滑
            water.setPhase(30d);//相位
            water.setWavelength(60d);
    
            WordToImage wordToImage = new DeformedComposedWordToImage(
                    fontGenerator,
                    backgroundGenerator,
                    textPaster,
                    new ImageDeformationByFilters(new ImageFilter[]{}),
                    new ImageDeformationByFilters(new ImageFilter[]{}),
                    new ImageDeformationByFilters(new ImageFilter[]{water})
                );
    
            addFactory(new GimpyFactory(wordGenerator, wordToImage));
        }
    }

    然后是提供生成验证图的静态方法的 CaptchaService.java . 这里就可以使用刚才建的ImageEngine来绘制验证图了

    public class CaptchaService
    {
        private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService(
                new FastHashMapCaptchaStore(),
                new CaptchaImageEngine(),
                180, 100000, 75000
            );
    
        private CaptchaService(){}
    
        public static BufferedImage getImageChallenge(String sid, Locale locale)
        {
            return instance.getImageChallengeForID(sid, locale);
        }
    
        public static BufferedImage getImageChallenge(String sid)
        {
            return instance.getImageChallengeForID(sid);
        }
    
        public static boolean validate(String sid, String input)
        {
            return instance.validateResponseForID(sid, input);
        }
    }

    这样, 在action中就可以直接调用了, 调用的方法分为两部分, 一部分是生成图片

    public String doGenerate()
        {
            try
            {
                // 获取session中的token用于生成验证图片,
                String token = getSession().getSession_token();
    
                // 生成验证图片
                BufferedImage challenge = CaptchaService.getImageChallenge(token);
    
                // 压缩为JPEG格式
                ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
                JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
                jpegEncoder.encode(challenge);
    
                // 置入action result的输出数据中
                this.put_streambytes("image/jpeg", jpegOutputStream.toByteArray());
            }
            catch (IllegalArgumentException e)
            {
                this.put_streambytes("image/jpeg", new byte[]{});
                logger.info("IllegalArgumentException");
                logger.debug("Exception Details", e);
            }
            catch (Exception e)
            {
                this.put_streambytes("image/jpeg", new byte[]{});
                logger.info("UnknownException");
                logger.debug("Exception Details", e);
            }
    
            return SUCCESS;
        }

    然后, 用于处理action result的方法, 会使用 ServletOutputStream 输出图片

    public class StreamProcessor {
    
        private static Logger logger = Logger.getLogger(RawProcessor.class);
    
        public static void process(HttpServletResponse res, String type, Object streamBytes)
        {
            try
            {
                res.setHeader("Cache-Control", "no-store");
                res.setHeader("Pragma", "no-cache");
                res.setDateHeader("Expires", 0);
                res.setContentType(type);
                ServletOutputStream responseOutputStream = res.getOutputStream();
                responseOutputStream.write((byte[])streamBytes);
                responseOutputStream.flush();
                responseOutputStream.close();
            }
            catch (Exception e)
            {
                logger.info("Unknown Exception");
                logger.debug("Exception details:", e);
            }
        }
    }

    另一方面, 需要在页面上添加对图片的引用, 因为需要制造点击刷新的效果, 使用javascript来生成html引用代码.
    前端的HTML是 (

     

    其中使用到的回调函数是

    function captcha_image(element_id, src) 
    {
        var joiner = '&';
        if (src.indexOf('?')== -1) joiner = '?';
        $("#"+element_id).html(' ');
    }

    后端响应这段js的action, 其作用, 是返回一段js代码, 让浏览器端去调用captcha_image()这个方法来生成引用图片的HTML代码

    public String doJsInclude()
        {
            DefaultRequestBean bean = new DefaultRequestBean();
            String elementId = bean.get("element");
            String output = "captcha_image(\""+elementId+"\",\""+baseLink("captcha_image")+"\");";
            this.put_raw_string(output);
            return SUCCESS;
        }

    在用户提交后, 用于验证用户提交的验证码内容的方法片段:

                String token = getSession().getSession_token();
                if (!CaptchaService.validate(token, this.captcha_input.toUpperCase()))
                {
                    flag = false;
                    this.put_error_msg("captcha_input", langRes.get("login_success"));
                }
                return flag;


  • 相关阅读:
    Android平台下基于XMPP的IM研究
    Android File数据存储
    Android 获取屏幕分辨率的方式
    Android TabHost 动态修改图标或者动态改变标题
    Android DatePickerDialog用法
    SharedPreference Demo
    progressdialog 去边框
    [LCT学习时的一些笔记]
    [ZJOI2007]最大半连通子图
    【Matrixtree Theorem学习笔记】
  • 原文地址:https://www.cnblogs.com/milton/p/4215076.html
Copyright © 2011-2022 走看看