首先创建一个CaptailCode类
1 package com.xiaoqiang.code; 2 3 import java.awt.*; 4 import java.awt.font.FontRenderContext; 5 import java.awt.geom.Rectangle2D; 6 import java.awt.image.BufferedImage; 7 import java.util.Random; 8 import javax.imageio.ImageIO; 9 import javax.servlet.http.HttpServletResponse; 10 11 /** 12 * 验证码工具类 13 */ 14 public class CaptailCode { 15 /** 16 * 验证码生成 17 * @param response 18 * @return 19 */ 20 public static String drawImage(HttpServletResponse response) 21 { //定义以字符串拼接的StringBuilder 22 StringBuilder stringBuilder=new StringBuilder(); 23 //准备产生4个字符串的随机数 24 for (int i = 0; i <4; i++) { 25 stringBuilder.append(randomChar()); 26 } 27 String code=stringBuilder.toString(); 28 29 //2:定义图片的宽度和高度 30 int width = 70; 31 int height = 25; 32 //简历bufferedImage对象,制定图片的长度和宽度以及色彩 33 BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR); 34 //3:获取到 Graphics2D 绘制对象,开始绘制验证码 35 Graphics2D g = bi.createGraphics(); 36 //4:设置文字的字体和大小 37 Font font = new Font("微软雅黑",Font.PLAIN,20); 38 //设置字体的颜色 39 Color color = new Color(0,0,0); 40 //设置字体 41 g.setFont(font); 42 //设置颜色 43 g.setColor(color); 44 //设置背景 45 g.setBackground(new Color(226,226,240)); 46 //开始绘制对象 47 g.clearRect(0,0,width,height); 48 //绘制形状,获取矩形对象 49 FontRenderContext context = g.getFontRenderContext(); 50 Rectangle2D bounds = font.getStringBounds(code,context); 51 //计算文件的坐标和间距 52 double x = (width - bounds.getWidth())/2; 53 double y = (height - bounds.getHeight())/2; 54 double ascent = bounds.getY(); 55 double baseY = y - ascent; 56 g.drawString(code,(int)x,(int)baseY); 57 //结束绘制 58 g.dispose(); 59 try { 60 ImageIO.write(bi,"jpg",response.getOutputStream()); 61 //刷新响应流 62 response.flushBuffer(); 63 }catch(Exception ex){ 64 ex.printStackTrace(); 65 } 66 67 return code; 68 } 69 private static char randomChar() 70 { //定义验证码需要的字母和数字 71 String string="QWERTYUIOPASDFGHJKLZXCVBNM123456"; 72 //定义随机对象 73 Random random=new Random(); 74 return string.charAt(random.nextInt(string.length())); 75 } 76 77 public static void main(String[] args) { 78 System.out.println(drawImage(null)); 79 } 80 }
再创建一个code.jsp文件
1 <%-- 2 Created by IntelliJ IDEA. 3 User: Administrator 4 Date: 2018731 0031 5 Time: 20:29 6 To change this template use File | Settings | File Templates. 7 --%> 8 <%@ page import="com.xiaoqiang.code.CaptailCode" %> 9 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 10 <% 11 //清空浏览器缓存 12 response.setHeader("pragma", "no-cache"); 13 response.setHeader("cache-control", "no-cache"); 14 response.setHeader("expires", "0"); 15 String code=CaptailCode.drawImage(response); 16 session.setAttribute("code", code); 17 //解决outputStream()问题 18 out.clear(); 19 out = pageContext.pushBody(); 20 %>
在index.jsp中显示验证码
1 <%-- 2 Created by IntelliJ IDEA. 3 User: Administrator 4 Date: 2018731 0031 5 Time: 18:47 6 To change this template use File | Settings | File Templates. 7 --%> 8 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 <html> 10 <head> 11 <title>java验证码</title> 12 <meta http-equiv="pragma" content="no-cache"> 13 <meta http-equiv="cache-control" content="no-cache"> 14 <meta http-equiv="expires" content="0"> 15 16 </head> 17 <body> 18 <a href="javascript:void(0);" onclick="changeCode()"><img src="code.jsp" alt="" id="code"></a> 19 <script> 20 function changeCode() 21 { 22 document.getElementById("code").src="code.jsp?d="+new Date(); 23 } 24 </script> 25 26 </body> 27 </html>
一个完整的验证码实例demo已经搞定了。
href="#"与href="javascript:void(0)"的区别
# 包含了一个位置信息,默认的锚是#top 也就是网页的上端。
而javascript:void(0), 仅仅表示一个死链接。
在页面很长的时候会使用 # 来定位页面的具体位置,格式为:# + id。
如果你要定义一个死链接请使用 javascript:void(0) 。
pushBody()的作用是保存当前的out对象,并更新PageContext中Page范围内Out对象。至于为什么要加上这句话,是因为JSP容器在处理完成请求后会调用releasePageConter方法释放所有的PageContestObject,并且同时调用getWriter方法。由于getWriter方法与在JSP页面中使用流相关的getOutputStream方法冲突,所以会造成这种异常,解决方法就是楼上给的一样,只需要在JSP页面的最后加上这两条语句。
out.clear();
out = pageContext.pushBody();