前言
为了防止恶意软件对“登录”等需要验证码的功能进行暴力破解,网站通常会使用验证码来增加安全性。验证码通常由一些经处理后的不规则的数字,字母及线条组成,其中线条是为了防止机器人解析验证码的真实内容。这个案例用的知识比较基础,需要用到servlet、Ajax、awt来实现。效果如下图所示,鼠标在输入框失去焦点时,触发校验函数进行验证:
哈哈哈,这个√和×有点丑啊,凑合看,反正没问题。
一.编写登录页login.jsp
本步主要完成以下的功能:
1.编写登录界面基本的元素
2.编写js程序,监听blur事件,输入框失去焦点时触发的函数
3.在校验函数中用ajax将用户输入的验证码传递给负责比对验证码的servlet
4.servlet对比,如果正确,则会返回√的图片,不正确会返回错×的图片
5.ajax将结果渲染到网页上
login.jsp的代码如下:
<%-- Created by IntelliJ IDEA. User: 害恶细君 Date: 2021/10/20 Time: 12:39 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>login</title> <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script> $(function (){ //通过验证码输入框的blur事件来触发函数 $("#checkCodeId").blur(function (){ let checkCode=$("#checkCodeId").val(); //在服务器端对验证码进行校验 $.post("CheckCodeServlet", "checkCode="+checkCode, function (result) { //根据返回的图片路径显示不同的提示图片 let resultHTML=$("<img src='"+result+"'height='115px' width='15px'/>"); $("#result").html(resultHTML); }) }) }); //刷新验证码 function reload($img){ $img.attr("src","img.jsp?t="+(new Date().getTime())); } </script> </head> <body> <table border="0"> <tr> <td>验证码</td> <td><input type="text" name="checkCode" id="checkCodeId" size="4"></td> <!--点击图片,重新加载验证码,img为验证码图片--> <td><a href="javascript:reload($('img'))"><img src="img.png"/></a></td> <!--验证码校验结果的图片--> <td id="result"></td> <td>看不清? 点击验证码更换一张</td> </tr> </table> </body> </html>
二.绘制验证码
MIME(Multipurpose Internet Mail Extension)多用途因特网邮件扩展协议。是描述信消息内容的因特网标准,用于设置文本,图像,音频,视频,以及其他应用程序专用的数据类型。开发者可以通过jsp中page指令的contentType属性设置页面的MIME类型。例如:contentType="image/jpeg"表示页面会被JPEG等图片格式。
下面通过设置MIME将一个jsp渲染成jpeg图片,用于生成验证码:
1.先编写img.jsp。代码如下:
<%@ page import="java.awt.*" %> <%@ page import="java.util.Random" %> <%@ page import="java.awt.image.BufferedImage" %> <%@ page import="javax.imageio.ImageIO" %><%-- Created by IntelliJ IDEA. User: 害恶细君 Date: 2021/10/20 Time: 16:06 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>img</title> </head> <body> <!--定义一些全局方法--> <%! //随机生成颜色 public Color getColor(){ Random random=new Random(); int r=random.nextInt(256); int g=random.nextInt(256); int b=random.nextInt(256); return new Color(r,g,b); } //生成验证码(随机生成4位数字) public String getNum(){ int ran= (int) (Math.random()*9000+1000); return String.valueOf(ran); } %> <% //禁用浏览器缓存,防止验证码不及时被加载 response.setHeader("pragma","no-cache"); response.setHeader("cache-control","no-cache"); response.setDateHeader("expires",0); //设置验证码图片:宽80px,gao30px,颜色类型为RGB BufferedImage image=new BufferedImage(80,30,BufferedImage.TYPE_INT_RGB); //创建画笔对象graphics Graphics graphics=image.getGraphics(); //填充验证码图片的背景色:从(0,0)开始填充,填充宽度为80px,填充高度为30px graphics.fillRect(0,0,80,30); /* *在验证码图片上随机生成60条干扰线段 * 线段的起始位置为(xBegin,yBegin),结束位置为(xEnd,yEnd) */ for (int i=0;i<60;i++){ Random random=new Random(); int xBegin=random.nextInt(80); int yBegin=random.nextInt(30); int xEnd=random.nextInt(xBegin+10); int yEnd=random.nextInt(yBegin+10); //设置线条的颜色 graphics.setColor(getColor()); //绘制线条 graphics.drawLine(xBegin,yBegin,xEnd,yEnd); } //设置验证码的字体格式:字体为serif,粗体,18像素 graphics.setFont(new Font("serif",Font.BOLD,18)); //设置验证码的字体颜色为黑色 graphics.setColor(Color.black); //获取验证码 String checkcode=getNum(); //验证码的各个数字之间增加一些间隔(空格) StringBuffer sb=new StringBuffer(); for (int i = 0; i < checkcode.length(); i++) { sb.append(checkcode.charAt(i)+" "); } //从坐标(15,20)开始绘制验证码 graphics.drawString(sb.toString(),15,20); //将验证码的值放入session中,供后续使用 session.setAttribute("CHECKCODE",checkcode); //将验证码绘制成JPEG格式 ImageIO.write(image,"jpeg",response.getOutputStream()); out.clear(); //验证码会被其他页面所引用 //JPEG格式的验证码生成后,会作为<img/>元素的src属性被其他页面引用 out=pageContext.pushBody(); %> </body> </html>
三.编写Servlet
在这个servlet里校验用户输入的验证码
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.io.IOException; import java.io.PrintWriter; @WebServlet("/CheckCodeServlet") public class CheckCodeServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取前端输入的验证码 String checkCodeClient=req.getParameter("checkCode"); String result= "imgs/wrong.png"; //获取服务器端session中的验证码 String checkcodeServlet= (String) req.getSession().getAttribute("CHECKCODE"); if (checkCodeClient.equals(checkcodeServlet)){ result="imgs/right.png"; } //以IO的方式,返回result值(提示图片路径) resp.setContentType("text/html;charset=UTF-8"); PrintWriter pw =resp.getWriter(); pw.write(result); pw.flush(); pw.close(); } }
okk,终于写完了,没想到居然写了快六千字,代码量有点小多啊。
接下来我要学后端框架了,先从Mybatis开始吧,那我们下期见,拜拜!