Web中如何生成验证码的方法

来源:互联网 发布:linux命令行切换用户 编辑:程序博客网 时间:2024/04/28 02:45

验证码的生成,这个在Web登陆系统中,我像大家都很常见了,所以我这里简单的介绍两种方法来实现这样的操作。

情况一:基于标准的Servlet的形式开发模式(非框架)

方法一:

Servlert代码:

package hnu.scw.properce;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.font.FontRenderContext;import java.awt.geom.Rectangle2D;import java.awt.image.BufferedImage;import java.io.ByteArrayOutputStream;/* * 演示验证码的生成到html中来进行显示  *  */import java.io.IOException;import java.util.Random;import javax.imageio.ImageIO;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletYanZhengMa extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {ByteArrayOutputStream output = new ByteArrayOutputStream();String code = drawImg(output);                //在这里还可以将验证码的信息保存到session中,方便进行登陆的时候判断是否正确try {ServletOutputStream out = response.getOutputStream();output.writeTo(out);} catch (IOException e) {e.printStackTrace();} }protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}       //绘制验证码private String drawImg(ByteArrayOutputStream output) {String code = "";for (int i = 0; i < 4; i++) {code += randomChar();}int width = 70;int height = 25;BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);Font font = new Font("Times New Roman", Font.PLAIN, 20);Graphics2D g = bi.createGraphics();g.setFont(font);Color color = new Color(66, 2, 82);g.setColor(color);g.setBackground(new Color(226, 226, 240));g.clearRect(0, 0, width, height);FontRenderContext context = g.getFontRenderContext();Rectangle2D bounds = font.getStringBounds(code, context);double x = (width - bounds.getWidth()) / 2;double y = (height - bounds.getHeight()) / 2;double ascent = bounds.getY();double baseY = y - ascent;g.drawString(code, (int) x, (int) baseY);g.dispose();try {ImageIO.write(bi, "jpg", output);} catch (IOException e) {e.printStackTrace();}return code;}        //生成四位数的验证码(这里就是在字母和数字之间产生,如果你需要更多的符号,那么就自己添加在String中就可以了哦)private char randomChar() {Random r = new Random();String s = "ABCDEFGHJKLMNPRSTUVWXYZ0123456789";return s.charAt(r.nextInt(s.length()));}}

Html代码:(页面简单点哈,能明白意思就可以了!!)

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><script type="text/javascript">//改变验证码          function change() {    var image = document.getElementById("image");    //注意的地方:1:服务器请求的路径不要写错了/ServletDemo/yanzhengma这个其实就是访问对应Servlet的地址     // 2:?" + new Date().getTime(); 为什么加了这个是因为要改变请求地址的内容,否则点击的话就直接从缓存中进行拿取,那么验证码就不会改变了    image.src = "/ServletDemo/yanzhengma?" + new Date().getTime();    }</script><body>   <form action="">        账 号<input type="text"><br><br>       密 码<input type="text"><br><br>       验证码<input type="text">    <img id="image" src="/ServletDemo/yanzhengma"><a href="javascript:change()">看不清楚,换一张</a>       </form></body></html>

备注:请注意我写的注释代码,这个地方非常非常重要!!!!!!!!!!!!!!!

方法二:(类似方法一,但是生成的方式有所变化,可以根据需要进行选择)

Servlert代码:

package hnu.scw.properce;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.image.BufferedImage;/* * 演示验证码的生成到html中来进行显示  *  */import java.io.IOException;import java.util.Random;import javax.imageio.ImageIO;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletYanZhengMa extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { getYanZhengMa(response);    //调用方法      }protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}/* * 生成验证码 */private void getYanZhengMa(HttpServletResponse response) {//设置一下颜色数组,为了验证码更加难辨认Color[] yanse = {Color.RED ,Color.BLACK ,Color.GREEN , Color.BLUE};//初始化验证码的宽和高int width = 100 ;int height = 60;//初始化图片缓冲器BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB) ;//初始化画笔Graphics gp  = bi.getGraphics(); //这里是用图片来进行初始化,否则不知道是画在哪里//设置画笔颜色gp.setColor(Color.RED);  //画一个矩形的外框gp.drawRect(0, 0, width, height);//设置矩形填充的颜色gp.setColor(Color.YELLOW);//填充背景(下面是从1,1开始填充,如果从0,0开始,那么外框也会被修改了,后面-2也是同理)gp.fillRect(1, 1, width-2, height-2);//生成要填充的内容Random random  = new Random();//设置验证码的干扰线(这是为了效果来进行开发的,可以没有)gp.setColor(Color.BLUE);//画30条干扰线for(int i=0 ; i<30 ;i++){gp.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));    //下面的是画点//gp.drawOval(random.nextInt(width), random.nextInt(height), 2, 2);}//设置填充的内容的颜色gp.setColor(Color.RED);//设置填充内容的大小gp.setFont(new Font("幼圆", Font.BOLD + Font.ITALIC, 20));//如果填充的内容要为中文的时候,需要这样处理String content ="全国我觉得嘎斯的获奖情况大手笔的吧区隔化akshldeqw";//要把上面的转为unicode编码,因为如果浏览器不支持中文的话就会出现乱码,如果在国内的话则没有什么影响//用在线工具转也可以,但最好用代码来进行转变,因为以后开发肯定是动态的一种方式最好//content ="\u5168\u56fd\u6211\u89c9\u5f97\u560e\u65af\u7684\u83b7\u5956\u60c5\u51b5\u5927\u624b\u7b14\u7684\u5427\u533a\u9694\u5316\u0061\u006b\u0073\u0068\u006c\u0064\u0065\u0071\u0077";for(int i =0 ; i < 4 ;i++){//gp.setColor(yanse[random.nextInt(3)]);设置填充的颜色随即化(为了验证码更复杂)char c =content.charAt(random.nextInt(content.length()));gp.drawString(c + "", 20 + 20*i, 30); //开始填充内容和位置}//如果想要验证码是数字的,则填充的内容为数字(生成四个数字)//for(int i=0 ; i<4 ;i++){//int number = random.nextInt(10);  //生成10以内的数字//gp.drawString(number + "", 20 + 20*i, 30); //开始填充内容和位置//}//设置不要缓存response.setHeader("Expires", -1+"");response.setHeader("Cache-control", "no-cache");response.setHeader("Pragma", "no-cache");//将验证码显示到对应的位置try {ImageIO.write(bi, "jpg", response.getOutputStream());} catch (IOException e) {e.printStackTrace();}}}

Html代码:

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><script type="text/javascript">//改变验证码          function change() {    var image = document.getElementById("image");    //注意的地方:1:服务器请求的路径不要写错了/ServletDemo/yanzhengma这个其实就是访问对应Servlet的地址     // 2:?" + new Date().getTime(); 为什么加了这个是因为要改变请求地址的内容,否则点击的话就直接从缓存中进行拿取,那么验证码就不会改变了    image.src = "/ServletDemo/yanzhengma?" + new Date().getTime();    }</script><body>   <form action="">        账 号<input type="text"><br><br>       密 码<input type="text"><br><br>       验证码<input type="text">    <img id="image" src="/ServletDemo/yanzhengma"><a href="javascript:change()">看不清楚,换一张</a>       </form></body></html>

总结:上面就是两种方法了,是不是很简单,其实不是想象的那么难。。当然,我这没有把登陆写进去,这个自己添加就可以了,只是注意一点就是在生成验证码的时候,要把验证码的字符保存到session中,否则在登陆判断验证码是否正确就没什么好方法啦。。。当然,你有其他的解决办法都可以哦~~


下面利用一个相对完整的Demo来进行演示(包含了登陆的判断了哦!!!)

情况二;基于SpringMVC框架

生成验证码的controller类的代码:

package com.mbfw.controller.system.secCode;import java.awt.Color;import java.awt.Font;import java.awt.Graphics2D;import java.awt.font.FontRenderContext;import java.awt.geom.Rectangle2D;import java.awt.image.BufferedImage;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.util.Random;import javax.imageio.ImageIO;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletResponse;import org.apache.shiro.SecurityUtils;import org.apache.shiro.session.Session;import org.apache.shiro.subject.Subject;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import com.mbfw.util.Const;/** * 类名称:SecCodeController 作者单位: *  * @version */@Controller@RequestMapping("/code")public class SecCodeController {@RequestMappingpublic void generate(HttpServletResponse response) {ByteArrayOutputStream output = new ByteArrayOutputStream();String code = drawImg(output);Subject currentUser = SecurityUtils.getSubject();Session session = currentUser.getSession();session.setAttribute(Const.SESSION_SECURITY_CODE, code);try {ServletOutputStream out = response.getOutputStream();output.writeTo(out);} catch (IOException e) {e.printStackTrace();}}private String drawImg(ByteArrayOutputStream output) {String code = "";for (int i = 0; i < 4; i++) {code += randomChar();}int width = 70;int height = 25;BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);Font font = new Font("Times New Roman", Font.PLAIN, 20);Graphics2D g = bi.createGraphics();g.setFont(font);Color color = new Color(66, 2, 82);g.setColor(color);g.setBackground(new Color(226, 226, 240));g.clearRect(0, 0, width, height);FontRenderContext context = g.getFontRenderContext();Rectangle2D bounds = font.getStringBounds(code, context);double x = (width - bounds.getWidth()) / 2;double y = (height - bounds.getHeight()) / 2;double ascent = bounds.getY();double baseY = y - ascent;g.drawString(code, (int) x, (int) baseY);g.dispose();try {ImageIO.write(bi, "jpg", output);} catch (IOException e) {e.printStackTrace();}return code;}private char randomChar() {Random r = new Random();String s = "ABCDEFGHJKLMNPRSTUVWXYZ0123456789";return s.charAt(r.nextInt(s.length()));}}
备注:其实这个和在标准的Servlet中的形式是一样的,只是用了SpringMVC的模式来编写而已,所以知道Servlet的方法,用其他的框架来写都会了!!!

jsp代码:(这里写个比较完整的)

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><%String path = request.getContextPath();%><!DOCTYPE html><html lang="en"><head><title>${pd.SYSNAME}</title><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><link rel="stylesheet" href="static/login/bootstrap.min.css" /><link rel="stylesheet" href="static/login/css/camera.css" /><link rel="stylesheet" href="static/login/bootstrap-responsive.min.css" /><link rel="stylesheet" href="static/login/matrix-login.css" /><link href="static/login/font-awesome.css" rel="stylesheet" /><script type="text/javascript" src="static/js/jquery-1.5.1.min.js"></script></head><body><divstyle="width:100%;text-align: center;margin: 0 auto;position: absolute;"><div id="loginbox"><form action="" method="post" name="loginForm"id="loginForm"><div class="control-group normal_text"><h3><img src="static/login/logo.png" alt="Logo" /></h3></div><div class="control-group"><div class="controls"><div class="main_input_box"><span class="add-on bg_lg"><i><img height="37" src="static/login/user.png" /></i></span><input type="text" name="loginname" id="loginname" value="" placeholder="请输入用户名" /></div></div></div><div class="control-group"><div class="controls"><div class="main_input_box"><span class="add-on bg_ly"><i><img height="37" src="static/login/suo.png" /></i></span><input type="password" name="password" id="password" placeholder="请输入密码" value="" /></div></div></div><div style="float:right;padding-right:10%;"><div style="float: left;margin-top:3px;margin-right:2px;"><font color="white">记住密码</font></div><div style="float: left;"><input name="form-field-checkbox" id="saveid" type="checkbox"onclick="savePaw();" style="padding-top:0px;" /></div></div><div class="form-actions"><div style="width:86%;padding-left:8%;"><div style="float: left;"><i><img src="static/login/yan.png" /></i></div><div style="float: left;" class="codediv"><input type="text" name="code" id="code" class="login_code"style="height:16px; padding-top:0px;" /></div><div style="float: left;"><i><img style="height:22px;" id="codeImg" alt="点击更换"title="点击更换" src="" /></i></div><span class="pull-right" style="padding-right:3%;"><ahref="javascript:quxiao();" class="btn btn-success">取消</a></span> <spanclass="pull-right"><a onclick="severCheck();"class="flip-link btn btn-info" id="to-recover">登录</a></span></div></div></form></div></div><div id="templatemo_banner_slide" class="container_wapper"><div class="camera_wrap camera_emboss" id="camera_slide"><div data-src="static/login/images/banner_slide_01.jpg"></div><div data-src="static/login/images/banner_slide_02.jpg"></div><div data-src="static/login/images/banner_slide_03.jpg"></div></div><!-- #camera_wrap_3 --></div><script type="text/javascript">//服务器校验function severCheck(){if(check()){var loginname = $("#loginname").val();var password = $("#password").val();var code = "qq123456789mbfw"+loginname+",mbfw,"+password+"QQ123456789mbfw"+",mbfw,"+$("#code").val();$.ajax({type: "POST",url: 'login_login',    data: {KEYDATA:code,tm:new Date().getTime()},dataType:'json',cache: false,success: function(data){if("success" == data.result){saveCookie();window.location.href="main/index";}else if("usererror" == data.result){$("#loginname").tips({side : 1,msg : "用户名或密码有误",bg : '#FF5080',time : 15});$("#loginname").focus();}else if("codeerror" == data.result){$("#code").tips({side : 1,msg : "验证码输入有误",bg : '#FF5080',time : 15});$("#code").focus();}else{$("#loginname").tips({side : 1,msg : "缺少参数",bg : '#FF5080',time : 15});$("#loginname").focus();}}});}}$(document).ready(function() {changeCode();$("#codeImg").bind("click", changeCode);});$(document).keyup(function(event) {if (event.keyCode == 13) {$("#to-recover").trigger("click");}});function genTimestamp() {var time = new Date();return time.getTime();}function changeCode() {$("#codeImg").attr("src", "code.do?t=" + genTimestamp());}//客户端校验function check() {if ($("#loginname").val() == "") {$("#loginname").tips({side : 2,msg : '用户名不得为空',bg : '#AE81FF',time : 3});$("#loginname").focus();return false;} else {$("#loginname").val(jQuery.trim($('#loginname').val()));}if ($("#password").val() == "") {$("#password").tips({side : 2,msg : '密码不得为空',bg : '#AE81FF',time : 3});$("#password").focus();return false;}if ($("#code").val() == "") {$("#code").tips({side : 1,msg : '验证码不得为空',bg : '#AE81FF',time : 3});$("#code").focus();return false;}$("#loginbox").tips({side : 1,msg : '正在登录 , 请稍后 ...',bg : '#68B500',time : 10});return true;}function savePaw() {if (!$("#saveid").attr("checked")) {$.cookie('loginname', '', {expires : -1});$.cookie('password', '', {expires : -1});$("#loginname").val('');$("#password").val('');}}function saveCookie() {if ($("#saveid").attr("checked")) {$.cookie('loginname', $("#loginname").val(), {expires : 7});$.cookie('password', $("#password").val(), {expires : 7});}}function quxiao() {$("#loginname").val('');$("#password").val('');}jQuery(function() {var loginname = $.cookie('loginname');var password = $.cookie('password');if (typeof(loginname) != "undefined"&& typeof(password) != "undefined") {$("#loginname").val(loginname);$("#password").val(password);$("#saveid").attr("checked", true);$("#code").focus();}});</script><script>//TOCMAT重启之后 点击左侧列表跳转登录首页 if (window != top) {top.location.href = location.href;}</script><script src="static/js/bootstrap.min.js"></script><script src="static/js/jquery-1.7.2.js"></script><script src="static/login/js/jquery.easing.1.3.js"></script><script src="static/login/js/jquery.mobile.customized.min.js"></script><script src="static/login/js/camera.min.js"></script><script src="static/login/js/templatemo_script.js"></script><script type="text/javascript" src="static/js/jquery.tips.js"></script><script type="text/javascript" src="static/js/jquery.cookie.js"></script></body></html>

备注:这里面的css和JS的引用,我没有写出来了,都是比较简单的,主要是用了jQuery还有Bootstap这两个插件的内容。如果只是想测试的话,只是样式不好看而已,都是次要的,关键在于功能可以就好了哈!!!

验证登陆的controller层代码:

/** * 请求登录,验证用户 */@RequestMapping(value = "/login_login", produces = "application/json;charset=UTF-8")@ResponseBodypublic Object login() throws Exception {Map<String, String> map = new HashMap<String, String>();PageData pd = new PageData();pd = this.getPageData();String errInfo = "";String KEYDATA[] = pd.getString("KEYDATA").replaceAll("qq123456789mbfw", "").replaceAll("QQ123456789mbfw", "").split(",mbfw,");boolean ismobile = false;if(pd.getString("ismobile")!=null && pd.getString("ismobile").toString().equals("true"))ismobile = true;if (null != KEYDATA && KEYDATA.length == 3) {// shiro管理的sessionSubject currentUser = SecurityUtils.getSubject();Session session = currentUser.getSession();String sessionCode = (String) session.getAttribute(Const.SESSION_SECURITY_CODE); // 获取session中的验证码String code = KEYDATA[2];if (null == code || "".equals(code)) {errInfo = "nullcode"; // 验证码为空} else {String USERNAME = KEYDATA[0];String PASSWORD = KEYDATA[1];pd.put("USERNAME", USERNAME);if ((Tools.notEmpty(sessionCode) && sessionCode.equalsIgnoreCase(code)) || ismobile) {String passwd = new SimpleHash("SHA-1", USERNAME, PASSWORD).toString(); // 密码加密pd.put("PASSWORD", passwd);pd = userService.getUserByNameAndPwd(pd);if (pd != null) {pd.put("LAST_LOGIN", DateUtil.getTime().toString());userService.updateLastLogin(pd);User user = new User();user.setUSER_ID(pd.getString("USER_ID"));user.setUSERNAME(pd.getString("USERNAME"));user.setPASSWORD(pd.getString("PASSWORD"));user.setNAME(pd.getString("NAME"));user.setRIGHTS(pd.getString("RIGHTS"));user.setROLE_ID(pd.getString("ROLE_ID"));user.setLAST_LOGIN(pd.getString("LAST_LOGIN"));user.setIP(pd.getString("IP"));user.setSTATUS(pd.getString("STATUS"));user.setUser_Permission((Integer)pd.get("user_Permission"));user.setSuperior_organization_name(pd.getString("superior_organization_name"));user.setOrganization_name(pd.getString("organization_name"));session.setAttribute(Const.SESSION_USER, user);session.setAttribute(Const.IS_MOBILE, ""+ismobile);session.removeAttribute(Const.SESSION_SECURITY_CODE);// shiro加入身份验证Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(USERNAME, PASSWORD);try {subject.login(token);} catch (AuthenticationException e) {errInfo = "身份验证失败!";}} else {errInfo = "usererror"; // 用户名或密码有误}} else {errInfo = "codeerror"; // 验证码输入有误}if (Tools.isEmpty(errInfo)) {errInfo = "success"; // 验证成功}}} else {errInfo = "error"; // 缺少参数}map.put("result", errInfo);return AppUtil.returnObject(new PageData(), map);}

验证通过后,显示系统的主界面controller层代码:

@RequestMapping(value = "/main/index")public ModelAndView login_index() {ModelAndView mv = new ModelAndView();mv.setViewName("jsp/login_success.jsp");return mv;}
登陆成功后显示的界面html代码----login_success.jsp

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body>  <h1>欢迎你</h1>  </body></html>

总结:好了,上面三种方法应该能够满足需要验证码的这个需求了,并且也给了一个完整的Demo进行演示。总的来说不是很难,但是想着用得多,所以我这就写篇文章来记录一下好了。如果有更好的方法,可以留言的哦!!我都会关注的啦。。大家一起。。加油加油。。

原创粉丝点击