目录
一、简介
1、什么是验证码?
验证码是“全自动区分计算机和人类的公证测试”(Completely Automated Public Turing test to tell Computers and Humans Apart)的缩写。它是一种用于识别用户是否为真实人类的技术。验证码通常包括一个随机生成的字符串,用户需要在输入框中输入正确的字符串以证明他们不是机器人。
2、验证码的种类
- 字符验证码:用户需要识别并输入一个包含随机字符的图像。
- 图像验证码:用户需要在一组图像中选择特定的图像,以证明他们是人类。
- 数学验证码:用户需要解决一个简单的数学问题,如加法或减法,以证明他们是人类。
- 音频验证码:用户需要听取和输入一个音频中的数字或单词。
- 滑块验证码:用户需要拖动一个滑块来证明他们是人类。
接下来我们着重介绍字符验证码的实现,这是常见验证码的种类之一。
3、字符验证码
首先创建一个新的JavaWeb项目,在项目中创建一个Servlet类。
接下来是代码的实现
1、实现CheckCodeServlet
package com.school.web.controller;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
@WebServlet("/CheckCodeServlet")
public class CheckCodeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//清除缓存
resp.setHeader("Pragma","No-cache");
resp.setHeader("Cache-Control","No-cache");
resp.setDateHeader("Expires",0);
//设置文件类型
resp.setContentType("image/gif");
int width = 100;
int height = 40;
//画板
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//创建画笔
Graphics g = image.createGraphics();
Font font = new Font("宋体",Font.BOLD,25);
g.setFont(font);
String realPath = req.getServletContext().getRealPath("/img/1.png");
Image img = ImageIO.read(new File(realPath));
g.drawImage(img,0,0,100,40,null);
String source = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String infor = "";
for (int i = 0; i < 4; i++) {
int index = new Random().nextInt(source.length() - 1);
char myCode = source.charAt(index);
Random random = new Random();
g.setColor(new Color(20+random.nextInt(120),20+random.nextInt(120),20+random.nextInt(120)));
g.drawString(myCode+"",15+i*20,20+new Random().nextInt(10));
g.drawLine(random.nextInt(100),random.nextInt(40),random.nextInt(100),random.nextInt(40));
infor += myCode;
}
req.getSession().setAttribute("infor",infor);
g.dispose();
OutputStream out = resp.getOutputStream();
ImageIO.write(image,"gif",out);
out.flush();
out.close();
}
}
在这个代码中 ,需要先清除缓存,如果不清除的话数据会存放到内存中在你下一次打开的时候就会生成你上一次的验证码,其次,就是需要用到
BufferedImage
对象,然后使用Graphics2D
对象绘制验证码图像。验证码文本是通过generateRandomString
方法生成的,并存储在Session中以供稍后验证。最后,我们将图像写入响应的输出流。
2、在JSP页面中显示验证码
<div class="login-box-body">
<p class="login-box-msg">登录系统</p>
<form action="${pageContext.request.contextPath}/TeacherController?action=login" method="post">
<div class="form-group has-feedback">
<input type="text" class="form-control" placeholder="用户名" name="name"value="${cookie.name.value}">${error.name}
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="password" class="form-control" placeholder="密码" name="password"value="${cookie.password.value}">${error.password}
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="form-group has-feedback" >
<input type="text" class="form-control" placeholder="验证码" style="width: 210px; float: left;" name="checkcode">  
<a style="cursor: hand" onclick="reload()"><img alt="加载中……" src="${pageContext.request.contextPath}/CheckCodeServlet" id="img" border="1"></a>
<span style="color: red">${codefail}</span>
<span style="color:red;">${fail}</span>
</div>
<div class="row">
<div class="col-xs-8">
<div class="checkbox icheck">
<label><input type="checkbox"> 记住 下次自动登录</label>
</div>
</div>
<!-- /.col -->
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">登录</button>
</div>
<!-- /.col -->
</div>
</form>
<!-- <div class="social-auth-links text-center">
<p>- 或者 -</p>
<a href="#" class="btn btn-block btn-social btn-facebook btn-flat"><i class="fa fa-qq"></i> 腾讯QQ用户登录</a>
<a href="#" class="btn btn-block btn-social btn-google btn-flat"><i class="fa fa-weixin"></i> 微信用户登录</a>
</div> -->
<!-- /.social-auth-links -->
<a href="#">忘记密码</a><br>
<a href="${pageContext.request.contextPath}/register_teacher.jsp" class="text-center">教师注册</a>   
<a href="${pageContext.request.contextPath}/register_student.jsp" class="text-center">学生注册</a>
</div>
3、验证用户输入是否与Session中存放的数据是否一致
package com.school.web.validate;
import com.school.domain.Teacher;
import java.util.HashMap;
import java.util.Map;
/**
* 数据验证
*/
public class ValidateDemo{
public static Map<String,String> validateLogin(Teacher teacher){
Map<String,String> error = new HashMap<>();
//验证名字
String name = teacher.getName();
if (name == null || "".equals(name.trim())){
error.put("name","用户名不能为空");
}else if (!(name.matches("\\w{6,18}"))){
error.put("name","用户名不合法");
}
//验证密码
String password = teacher.getPassword();
if (password == null || "".equals(password.trim())){
error.put("password","密码不能为空");
}else if (!(name.matches("[a-zA-Z0-9]{6,18}"))){
error.put("password","密码不合法");
}
return error;
}
}
4、接下来就是验证码的验证,这里的验证码验证要在验证用户名和密码前完成。
package com.school.web.controller;
import com.school.dao.impl.TeacherDaoImpl;
import com.school.domain.Page;
import com.school.domain.Teacher;
import com.school.service.TeacherService;
import com.school.service.impl.TeacherServiceImpl;
import com.school.web.validate.ValidateDemo;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
@WebServlet("/TeacherController")
public class TeacherController extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
//登录
if ("login".equals(action)) {
String checkcode = req.getParameter("checkcode");
String infor = (String) req.getSession().getAttribute("infor");
//验证码验证
if (checkcode != null && checkcode.equalsIgnoreCase(infor)){
Teacher teacher = new Teacher();
try {
BeanUtils.populate(teacher,req.getParameterMap());
Map<String, String> error = ValidateDemo.validateLogin(teacher);
if (error.isEmpty()){
String name = req.getParameter("name");
String password = req.getParameter("password");
TeacherService userService = new TeacherServiceImpl();
boolean flag = userService.login(name, password);
if (flag){
//判断是否需要用户名和密码
String[] autoLogins = req.getParameterValues("remember");
if (autoLogins != null && autoLogins.length > 0){
//记录用户名和密码
Cookie nameCookie = new Cookie("name", name);
Cookie psdCookie = new Cookie("password",password);
nameCookie.setMaxAge(2592000);
psdCookie.setMaxAge(2592000);
nameCookie.setPath("/schoolpro02");
psdCookie.setPath("/schoolpro02");
resp.addCookie(nameCookie);
resp.addCookie(psdCookie);
//设置一个登录成功的标志
req.getSession().setAttribute("name",name);
req.getRequestDispatcher("/pages/index.jsp").forward(req,resp);
}else {
req.getSession().setAttribute("name",name);
req.getRequestDispatcher("/pages/index.jsp").forward(req,resp);
}
}else {
req.setAttribute("fail","登录失败!");
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
}else {
req.setAttribute("error",error);
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}else {
req.setAttribute("codefail","验证码错误,请重新输入");
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
Teacher teacher = new Teacher();
}
}
}
}
4、效果演示
首先是验证码的自由切换这里,其次是不输入验证码然后提示重新输入,然后输入完之后进入主页。