【JavaWeb】实现网页验证码

导读:常用的验证码有文本+数字,或者是算式验证码。可以自己编写,来生成验证码。亦或是使用第三方库,来生成验证码。


字母数字验证码

实现形如下图的验证码:

                                                                

编写一个验证码生成类,首先写一个产生随机字符的方法:

public class CaptchaCode {
    private static char randomChar(){
        String string="QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
        Random random=new Random();
        return string.charAt(random.nextInt(string.length()));
    }
}

然后写一个生成验证码图片的方法:

    public static String drawImage(HttpServletResponse response){
        //1.拼接字符串的类
        StringBuilder builder=new StringBuilder();
        //产生4位验证码
        for (int i = 0; i <4 ; i++) {
            builder.append(randomChar());
        }
        String code=builder.toString();
        //2.定义图片的宽度和高度
        int width=120;
        int height=25;
        //建立BufferedImage对象,指定图片缓冲流的长宽度和样式
        BufferedImage bi=new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
        //3.获取Graphics2d绘制对象,开始绘制验证码。图片最终会注入到缓冲流中
        Graphics2D graph=bi.createGraphics();
        //4.设置字体和大小
        Font font=new Font("宋体",Font.PLAIN,20);
        Color color=new Color(0,255,255);
        graph.setFont(font);
        graph.setColor(color);
        graph.setBackground(new Color(0,0,0));
        //绘制形状,一般是矩形
        graph.clearRect(0,0,width,height);
        //创建字体对象
        FontRenderContext context=graph.getFontRenderContext();
        //获得文字的边界
        Rectangle2D bounds=font.getStringBounds(code,context);
        //计算坐标和间距,以便字体放在矩形的正中央
        double x=(width-bounds.getWidth())/2;
        double y=(height-bounds.getHeight())/2;
        double acsent=bounds.getY();
        double baseY=y-acsent;
        //在矩形中绘制字体
        graph.drawString(code,(int)x,(int)baseY);
        graph.dispose();
        //保存到响应的输出流
        try {
            ImageIO.write(bi,"jpg",response.getOutputStream());
            //刷新响应流
            response.flushBuffer();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //用于验证码的对比和存储
        return code;
    }

编写code.jsp,调用上面的方法,在响应中添加一个验证码图片流。

<%
    //清空浏览器缓存
    response.setHeader("pragma","no-cache");
    response.setHeader("cache-control","no-cache");
    response.setHeader("expires","0");
    //获取验证码字符,用于比对
    String code=CaptchaCode.drawImage(response);
    session.setAttribute("code",code);
    out.clear();
    out=pageContext.pushBody();
%>

在主页中,令img标签的源为上面的code.jsp,同时添加一个超链接,当点击超链接后,将img标签的src重新设置,每次点击都传入一个不同的请求,用于更换验证码。


看不清?换一张

算术验证码

实现如下形式的验证码:

                                                                                        

新建一个获取随机背景色的方法

private static Color getRandomColor(int fc,int bc){
    Random random=new Random();
    if(fc>255) fc=255;
    if(bc>255) bc=255;
    int r=fc+random.nextInt(bc-fc);
    int g=fc+random.nextInt(bc-fc);
    int b=fc+random.nextInt(bc-fc);
    return new Color(r,g,b);
    }

编写产生算术验证码方法,与之前的类似,只不过需要绘制干扰线

public static String drawImageVerificate(HttpServletResponse response){
    int width=100,height=30;
    BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
    Graphics2D graph=image.createGraphics();
    Random random=new Random();
    //设置背景
    graph.setColor(getRandomColor(240,250));
    graph.setFont(new Font("微软雅黑",Font.PLAIN,22));
    graph.fillRect(0,0,width,height);
    //设置干扰线颜色并绘制线条在图片中
    graph.setColor(getRandomColor(180,230));
    //100条
    for (int i = 0; i <100 ; i++) {
        int x=random.nextInt(width);
        int y=random.nextInt(height);
        int x1=random.nextInt(60);
        int y1=random.nextInt(60);
        graph.drawLine(x,y,x1,y1);
        }
    //算术表达式拼接
    int num1=(int)(Math.random()*10+1);
    int num2=(int)(Math.random()*10+1);
    int optor=random.nextInt(3);
    int result=0;    
    String optorstr="";
    switch (optor){
        case 0 :optorstr="+";result=num1+num2;break;
        case 1 :optorstr="-";result=num1-num2;break;
        case 2 :optorstr="*";result=num1*num2;break;
        }
    //拼接算术表达式
    String calc=num1+" "+optorstr+" "+num2+" = ? ";
    //设置表达式颜色
    graph.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
    //绘制表达式
    graph.drawString(calc,5,25);
    graph.dispose();
    try {
        ImageIO.write(image,"JPEG",response.getOutputStream());
        return String.valueOf(result);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

code.jsp和index.jsp与之前一样。


使用Kaptcha框架生成验证码

                                                                                

使用框架来产生验证码十分方便和快捷,可以指定各种样式。这里使用了Kaptcha框架,首先需要导入相关jar包,然后在web.xml中进行配置。

第一行比较重要,指定了生成验证码图片的地址为/kaptcha.jpg。


    Kaptcha
    /kaptcha.jpg



    Kaptcha
    com.google.code.kaptcha.servlet.KaptchaServlet
    
    
        kaptcha.border
        no
    
    
        kaptcha.image.width
        100
    
    
        kaptcha.image.height
        40
    
    
    
        kaptcha.textproducer.font.size
        28
    
    
    
        kaptcha.textproducer.char.string
        qwertyuiopasdfghjklzxcvbnm123456789
    
    
        kaptcha.textproducer.char.length
        4
    
    
    
        kaptcha.noise.impl
        com.google.code.kaptcha.impl.DefaultNoise
    
    
     
        kaptcha.obscurificator.impl
        com.google.code.kaptcha.impl.FishEyeGimpy
     
     
         
         kaptcha.session.key
         kcode
     

最后需要将生成的验证码,通过kaptcha.session.key来保存,通过kcode来访问生存的验证码字符串


字符串校验

首先编写一个用于测试的jsp。

验证码:

然后编写一个js脚本,当用于点击图片的时候,产生一个新的验证码:

然后再编写一个js脚本,绑定“登录”按键。

最后编写url为login的Servlet:

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("UTF-8");
        //获取浏览器输出流对象,用于输出到ajax
        PrintWriter out = response.getWriter();
        //获取用户传递过来的验证码
        String code = request.getParameter("code");
        //获取验证码框架产生的验证码(会话中存储的验证码)
        String sessionCode = (String)request.getSession().getAttribute("kcode");
        if(code!=null&sessionCode!=null) {
            //如果用户输入的验证码和产生在服务器端的验证码一致,那么就告诉用户输入正确
            if (code.equalsIgnoreCase(sessionCode)) {
                //登录逻辑、注册逻辑等相关的业务操作
                out.print("success");
            } else {
                out.print("fail");
            }
        }
        out.flush();
        out.close();
    }

这样就完成了验证码的校验

你可能感兴趣的:(Java,JavaWeb)